feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
31
frontend/packages/agent-ide/tool/.storybook/main.js
Normal file
31
frontend/packages/agent-ide/tool/.storybook/main.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { mergeConfig } from 'vite';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
|
||||
/** @type { import('@storybook/react-vite').StorybookConfig } */
|
||||
const config = {
|
||||
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.tsx'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-onboarding',
|
||||
'@storybook/addon-interactions',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
viteFinal: config =>
|
||||
mergeConfig(config, {
|
||||
plugins: [
|
||||
svgr({
|
||||
svgrOptions: {
|
||||
native: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
};
|
||||
export default config;
|
||||
14
frontend/packages/agent-ide/tool/.storybook/preview.js
Normal file
14
frontend/packages/agent-ide/tool/.storybook/preview.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/** @type { import('@storybook/react').Preview } */
|
||||
const preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
5
frontend/packages/agent-ide/tool/.stylelintrc.js
Normal file
5
frontend/packages/agent-ide/tool/.stylelintrc.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { defineConfig } = require('@coze-arch/stylelint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: [],
|
||||
});
|
||||
16
frontend/packages/agent-ide/tool/README.md
Normal file
16
frontend/packages/agent-ide/tool/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# tool-hooks
|
||||
|
||||
定位为Bot Creator业务子package,里面的通用组件慢慢往外抽。
|
||||
|
||||
## Features
|
||||
|
||||
- [x] eslint & ts
|
||||
- [x] esm bundle
|
||||
- [x] umd bundle
|
||||
- [x] storybook
|
||||
|
||||
## Commands
|
||||
|
||||
- init: `rush update`
|
||||
- dev: `npm run dev`
|
||||
- build: `npm run build`
|
||||
0
frontend/packages/agent-ide/tool/__tests__/.gitkeep
Normal file
0
frontend/packages/agent-ide/tool/__tests__/.gitkeep
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 React, { type FC } from 'react';
|
||||
|
||||
import {
|
||||
renderHook,
|
||||
type WrapperComponent,
|
||||
} from '@testing-library/react-hooks';
|
||||
import { ToolGroupKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useAbilityConfig } from '../../src/hooks/builtin/use-ability-config';
|
||||
import {
|
||||
AbilityAreaContextProvider,
|
||||
type ToolEntryCommonProps,
|
||||
ToolView,
|
||||
ToolKey,
|
||||
AbilityScope,
|
||||
GroupingContainer,
|
||||
} from '../../src';
|
||||
|
||||
vi.stubGlobal('IS_DEV_MODE', false);
|
||||
|
||||
type ITestComponentProps = ToolEntryCommonProps;
|
||||
|
||||
const TestComponent: FC<ITestComponentProps> = ({ title, toolKey }) => (
|
||||
<div>
|
||||
test{title} {toolKey}
|
||||
</div>
|
||||
);
|
||||
|
||||
describe('useAbilityConfig', () => {
|
||||
test('useAbilityConfig', () => {
|
||||
const wrapper: WrapperComponent<{ children }> = ({ children }) => (
|
||||
<AbilityAreaContextProvider mode={0}>
|
||||
{children}
|
||||
<ToolView>
|
||||
<GroupingContainer
|
||||
toolGroupKey={ToolGroupKey.CHARACTER}
|
||||
title="testGroup"
|
||||
>
|
||||
<TestComponent toolKey={ToolKey.ONBOARDING} title="demo" />
|
||||
</GroupingContainer>
|
||||
</ToolView>
|
||||
</AbilityAreaContextProvider>
|
||||
);
|
||||
|
||||
const { result } = renderHook(() => useAbilityConfig(), { wrapper });
|
||||
|
||||
expect(result.current).toEqual({
|
||||
abilityKey: ToolKey.ONBOARDING,
|
||||
scope: AbilityScope.TOOL,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 { ToolGroupKey, ToolKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import {
|
||||
createToolAreaStore,
|
||||
type ToolAreaStore,
|
||||
} from '../../src/store/tool-area';
|
||||
|
||||
let useToolAreaStore: ToolAreaStore;
|
||||
|
||||
vi.stubGlobal('IS_DEV_MODE', false);
|
||||
|
||||
beforeEach(() => {
|
||||
const newToolAreaStore = createToolAreaStore();
|
||||
useToolAreaStore = newToolAreaStore;
|
||||
});
|
||||
|
||||
const testToolKeyConfig = {
|
||||
toolGroupKey: ToolGroupKey.DIALOG,
|
||||
toolKey: ToolKey.PLUGIN,
|
||||
toolTitle: '工具1',
|
||||
hasValidData: false,
|
||||
};
|
||||
|
||||
const repeatTestToolKeyConfig = {
|
||||
toolGroupKey: ToolGroupKey.CHARACTER,
|
||||
toolKey: ToolKey.PLUGIN,
|
||||
toolTitle: 'Repeat 工具1',
|
||||
hasValidData: false,
|
||||
};
|
||||
|
||||
const testToolGroup = {
|
||||
toolGroupKey: ToolGroupKey.DIALOG,
|
||||
groupTitle: '测试分组',
|
||||
};
|
||||
|
||||
describe('useToolAreaStore', () => {
|
||||
test('appendIntoRegisteredToolKeyConfigList add one', () => {
|
||||
const { appendIntoRegisteredToolKeyConfigList } =
|
||||
useToolAreaStore.getState();
|
||||
|
||||
appendIntoRegisteredToolKeyConfigList(testToolKeyConfig);
|
||||
|
||||
expect(
|
||||
useToolAreaStore.getState().registeredToolKeyConfigList,
|
||||
).toStrictEqual([testToolKeyConfig]);
|
||||
});
|
||||
|
||||
test('appendIntoRegisteredToolKeyConfigList repeat filter', () => {
|
||||
const { appendIntoRegisteredToolKeyConfigList } =
|
||||
useToolAreaStore.getState();
|
||||
|
||||
appendIntoRegisteredToolKeyConfigList(testToolKeyConfig);
|
||||
appendIntoRegisteredToolKeyConfigList(repeatTestToolKeyConfig);
|
||||
|
||||
expect(
|
||||
useToolAreaStore.getState().registeredToolKeyConfigList,
|
||||
).toStrictEqual([testToolKeyConfig]);
|
||||
});
|
||||
|
||||
test('hasToolKeyInRegisteredToolKeyList', () => {
|
||||
const { appendIntoRegisteredToolKeyConfigList } =
|
||||
useToolAreaStore.getState();
|
||||
|
||||
appendIntoRegisteredToolKeyConfigList(testToolKeyConfig);
|
||||
|
||||
expect(
|
||||
useToolAreaStore
|
||||
.getState()
|
||||
.hasToolKeyInRegisteredToolKeyList(testToolKeyConfig.toolKey),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
useToolAreaStore
|
||||
.getState()
|
||||
.hasToolKeyInRegisteredToolKeyList(ToolKey.DATABASE),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('appendIntoInitialedToolKeyList', () => {
|
||||
const { appendIntoInitialedToolKeyList } = useToolAreaStore.getState();
|
||||
|
||||
appendIntoInitialedToolKeyList(ToolKey.PLUGIN);
|
||||
|
||||
expect(useToolAreaStore.getState().initialedToolKeyList).toStrictEqual([
|
||||
ToolKey.PLUGIN,
|
||||
]);
|
||||
});
|
||||
|
||||
test('hasToolKeyInInitialedToolKeyList', () => {
|
||||
const { appendIntoInitialedToolKeyList } = useToolAreaStore.getState();
|
||||
|
||||
appendIntoInitialedToolKeyList(ToolKey.PLUGIN);
|
||||
|
||||
expect(
|
||||
useToolAreaStore
|
||||
.getState()
|
||||
.hasToolKeyInInitialedToolKeyList(ToolKey.PLUGIN),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
useToolAreaStore
|
||||
.getState()
|
||||
.hasToolKeyInInitialedToolKeyList(ToolKey.ONBOARDING),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('setToolHasValidData', () => {
|
||||
const { appendIntoRegisteredToolKeyConfigList, setToolHasValidData } =
|
||||
useToolAreaStore.getState();
|
||||
|
||||
appendIntoRegisteredToolKeyConfigList(testToolKeyConfig);
|
||||
|
||||
setToolHasValidData({
|
||||
toolKey: testToolKeyConfig.toolKey,
|
||||
hasValidData: true,
|
||||
});
|
||||
|
||||
expect(
|
||||
useToolAreaStore.getState().registeredToolKeyConfigList,
|
||||
).toStrictEqual([
|
||||
{
|
||||
...testToolKeyConfig,
|
||||
hasValidData: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('appendIntoRegisteredToolGroupList', () => {
|
||||
const { appendIntoRegisteredToolGroupList } = useToolAreaStore.getState();
|
||||
|
||||
appendIntoRegisteredToolGroupList(testToolGroup);
|
||||
|
||||
expect(useToolAreaStore.getState().registeredToolGroupList).toStrictEqual([
|
||||
testToolGroup,
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 { generateError } from '../../src/utils/error';
|
||||
|
||||
describe('error', () => {
|
||||
test('test error', () => {
|
||||
const testMessage = 'test error';
|
||||
const result = generateError(testMessage);
|
||||
|
||||
expect(result).toEqual(
|
||||
new Error(`[Bot Platform Tool Hooks]: ${testMessage}`),
|
||||
);
|
||||
});
|
||||
});
|
||||
12
frontend/packages/agent-ide/tool/config/rush-project.json
Normal file
12
frontend/packages/agent-ide/tool/config/rush-project.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"operationSettings": [
|
||||
{
|
||||
"operationName": "test:cov",
|
||||
"outputFolderNames": ["coverage"]
|
||||
},
|
||||
{
|
||||
"operationName": "ts-check",
|
||||
"outputFolderNames": ["./dist"]
|
||||
}
|
||||
]
|
||||
}
|
||||
7
frontend/packages/agent-ide/tool/eslint.config.js
Normal file
7
frontend/packages/agent-ide/tool/eslint.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const { defineConfig } = require('@coze-arch/eslint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
packageRoot: __dirname,
|
||||
preset: 'web',
|
||||
rules: {},
|
||||
});
|
||||
97
frontend/packages/agent-ide/tool/package.json
Normal file
97
frontend/packages/agent-ide/tool/package.json
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"name": "@coze-agent-ide/tool",
|
||||
"version": "0.0.1",
|
||||
"description": "tool hooks & components & context",
|
||||
"license": "Apache-2.0",
|
||||
"author": "liushuoyan@bytedance.com",
|
||||
"maintainers": [],
|
||||
"main": "src/index.ts",
|
||||
"unpkg": "./dist/umd/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./src/index.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-agent-ide/bot-editor-context-store": "workspace:*",
|
||||
"@coze-agent-ide/tool-config": "workspace:*",
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-error": "workspace:*",
|
||||
"@coze-arch/bot-flags": "workspace:*",
|
||||
"@coze-arch/bot-hooks": "workspace:*",
|
||||
"@coze-arch/bot-icons": "workspace:*",
|
||||
"@coze-arch/bot-semi": "workspace:*",
|
||||
"@coze-arch/bot-studio-store": "workspace:*",
|
||||
"@coze-arch/bot-typings": "workspace:*",
|
||||
"@coze-arch/bot-utils": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-arch/logger": "workspace:*",
|
||||
"@coze-data/knowledge-modal-base": "workspace:*",
|
||||
"@coze-foundation/global-store": "workspace:*",
|
||||
"@coze-studio/bot-detail-store": "workspace:*",
|
||||
"@coze-studio/components": "workspace:*",
|
||||
"@douyinfe/semi-foundation": "2.36.1-alpha.2",
|
||||
"@douyinfe/semi-icons": "^2.36.0",
|
||||
"ahooks": "^3.7.8",
|
||||
"classnames": "^2.3.2",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"immer": "^10.0.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoid": "^4.0.2",
|
||||
"react-error-boundary": "^4.0.9",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coze-arch/eslint-config": "workspace:*",
|
||||
"@coze-arch/postcss-config": "workspace:*",
|
||||
"@coze-arch/stylelint-config": "workspace:*",
|
||||
"@coze-arch/tailwind-config": "workspace:*",
|
||||
"@coze-arch/ts-config": "workspace:*",
|
||||
"@coze-arch/vitest-config": "workspace:*",
|
||||
"@rollup/plugin-commonjs": "^24.0.0",
|
||||
"@rollup/plugin-json": "~6.0.0",
|
||||
"@rollup/plugin-node-resolve": "~15.0.1",
|
||||
"@rollup/plugin-replace": "^4.0.0",
|
||||
"@swc/core": "^1.3.35",
|
||||
"@swc/helpers": "^0.4.12",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@types/lodash-es": "^4.17.10",
|
||||
"@types/react": "18.2.37",
|
||||
"@types/react-dom": "18.2.15",
|
||||
"@vitest/coverage-v8": "~3.0.5",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"less": "^4.2.0",
|
||||
"less-loader": "~11.1.3",
|
||||
"postcss": "^8.4.32",
|
||||
"react": "~18.2.0",
|
||||
"react-dom": "~18.2.0",
|
||||
"rollup": "^4.9.0",
|
||||
"rollup-plugin-cleanup": "^3.2.1",
|
||||
"rollup-plugin-node-externals": "^6.1.2",
|
||||
"rollup-plugin-postcss": "^4.0.2",
|
||||
"rollup-plugin-ts": "^3.1.1",
|
||||
"stylelint": "^15.11.0",
|
||||
"tailwindcss": "~3.3.3",
|
||||
"typescript": "~5.8.2",
|
||||
"vite": "^4.3.9",
|
||||
"vite-plugin-svgr": "~3.3.0",
|
||||
"vitest": "~3.0.5",
|
||||
"webpack": "~5.91.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 FC, type PropsWithChildren } from 'react';
|
||||
|
||||
import { type BotMode } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { InvisibleToolController } from '../invisible-tool-controller';
|
||||
import { type IEventCallbacks } from '../../typings/event-callbacks';
|
||||
import {
|
||||
type IPreferenceContext,
|
||||
PreferenceContextProvider,
|
||||
} from '../../context/preference-context';
|
||||
import { AbilityAreaContextProvider } from '../../context/ability-area-context';
|
||||
|
||||
type IProps = {
|
||||
eventCallbacks?: Partial<IEventCallbacks>;
|
||||
mode: BotMode;
|
||||
modeSwitching: boolean;
|
||||
isInit: boolean;
|
||||
} & Partial<IPreferenceContext>;
|
||||
|
||||
export const AbilityAreaContainer: FC<PropsWithChildren<IProps>> = props => {
|
||||
const {
|
||||
children,
|
||||
eventCallbacks,
|
||||
enableToolHiddenMode,
|
||||
isReadonly,
|
||||
mode,
|
||||
modeSwitching,
|
||||
isInit,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<PreferenceContextProvider
|
||||
enableToolHiddenMode={enableToolHiddenMode}
|
||||
isReadonly={isReadonly}
|
||||
>
|
||||
<AbilityAreaContextProvider
|
||||
eventCallbacks={eventCallbacks}
|
||||
mode={mode}
|
||||
modeSwitching={modeSwitching}
|
||||
isInit={isInit}
|
||||
>
|
||||
<InvisibleToolController />
|
||||
{children}
|
||||
</AbilityAreaContextProvider>
|
||||
</PreferenceContextProvider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { IconCozEdit, IconCozPlus } from '@coze-arch/coze-design/icons';
|
||||
import { IconButton } from '@coze-arch/coze-design';
|
||||
|
||||
import { ToolTooltip } from '../tool-tooltip';
|
||||
import { type ToolButtonCommonProps } from '../../typings/button';
|
||||
|
||||
interface AddButtonProps extends ToolButtonCommonProps {
|
||||
iconName?: 'add' | 'edit';
|
||||
enableAutoHidden?: boolean;
|
||||
}
|
||||
|
||||
export const AddButton: FC<AddButtonProps> = ({
|
||||
onClick,
|
||||
tooltips,
|
||||
disabled,
|
||||
loading,
|
||||
iconName = 'add',
|
||||
enableAutoHidden,
|
||||
...restProps
|
||||
}) => {
|
||||
const readonly = useBotDetailIsReadonly();
|
||||
|
||||
if (readonly && enableAutoHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ToolTooltip content={tooltips}>
|
||||
<div>
|
||||
<IconButton
|
||||
icon={
|
||||
iconName === 'add' ? (
|
||||
<IconCozPlus className="text-base coz-fg-secondary" />
|
||||
) : (
|
||||
<IconCozEdit className="text-base coz-fg-secondary" />
|
||||
)
|
||||
}
|
||||
loading={loading}
|
||||
onClick={onClick}
|
||||
size="small"
|
||||
color="secondary"
|
||||
disabled={!!disabled}
|
||||
data-testid={restProps['data-testid']}
|
||||
/>
|
||||
</div>
|
||||
</ToolTooltip>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import { type FC, type PropsWithChildren } from 'react';
|
||||
|
||||
import { AbilityScope, type AgentSkillKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { AbilityConfigContextProvider } from '../../context/ability-config-context';
|
||||
|
||||
interface IProps {
|
||||
agentSkillKey?: AgentSkillKey;
|
||||
}
|
||||
|
||||
export const AgentSkillContainer: FC<PropsWithChildren<IProps>> = ({
|
||||
children,
|
||||
agentSkillKey,
|
||||
}) => (
|
||||
<ErrorBoundary fallback={<div>error</div>}>
|
||||
<AbilityConfigContextProvider
|
||||
abilityKey={agentSkillKey}
|
||||
scope={AbilityScope.AGENT_SKILL}
|
||||
>
|
||||
{children}
|
||||
</AbilityConfigContextProvider>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
@@ -0,0 +1,100 @@
|
||||
.content-block {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: var(--light-usage-fill-color-fill-0, rgb(46 46 56 / 4%));
|
||||
border-radius: 8px;
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
.header-icon-arrow {
|
||||
cursor: pointer;
|
||||
|
||||
transform: rotate3d(0, 0, 0, 0);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
margin-right: 3px;
|
||||
|
||||
transition: transform .2s linear 0s;
|
||||
|
||||
&.open {
|
||||
transform: rotate3d(0, 0, 1, 90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
display: flex;
|
||||
margin-right: 8px;
|
||||
|
||||
>img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 20px;
|
||||
|
||||
.label {
|
||||
margin-left: 4px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
line-height: 22px;
|
||||
color: var(--light-usage-text-color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
.popover {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
|
||||
&>svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
color: #A7A9B0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-collapsible-wrapper {
|
||||
padding-left: 0 !important;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-content {
|
||||
padding-left: 0;
|
||||
|
||||
&.open {
|
||||
:global {
|
||||
.semi-collapsible-wrapper,
|
||||
.semi-collapsible-wrapper [x-semi-prop] {
|
||||
overflow: visible !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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 CSSProperties,
|
||||
forwardRef,
|
||||
type PropsWithChildren,
|
||||
type ReactNode,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Tooltip, Collapsible } from '@coze-arch/bot-semi';
|
||||
import { IconInfo, IconArrowRight } from '@coze-arch/bot-icons';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
export type AgentContentBlockProps = PropsWithChildren<{
|
||||
allowToggleCollapsible?: boolean;
|
||||
title?: ReactNode;
|
||||
actionButton?: ReactNode;
|
||||
tooltip?: string | ReactNode;
|
||||
maxContentHeight?: number;
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
style?: CSSProperties;
|
||||
defaultExpand?: boolean;
|
||||
autoExpandWhenDomChange?: boolean;
|
||||
}>;
|
||||
|
||||
export interface ContentRef {
|
||||
setOpen?: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
export const AgentSkillContentBlock = forwardRef<
|
||||
ContentRef,
|
||||
AgentContentBlockProps
|
||||
>(
|
||||
(
|
||||
{
|
||||
allowToggleCollapsible = true,
|
||||
children,
|
||||
title,
|
||||
actionButton,
|
||||
maxContentHeight,
|
||||
tooltip,
|
||||
className,
|
||||
contentClassName,
|
||||
style,
|
||||
defaultExpand = true,
|
||||
autoExpandWhenDomChange,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const [isOpen, setIsOpen] = useState(defaultExpand);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const childNodeRef = useRef<HTMLDivElement>(null);
|
||||
const actionDivRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const target = childNodeRef.current;
|
||||
if (autoExpandWhenDomChange && target && allowToggleCollapsible) {
|
||||
const config = { attributes: true, childList: true, subtree: true };
|
||||
// 只有开启了dom改变自动展开功能才启动
|
||||
const callback: MutationCallback = mutationList => {
|
||||
if (mutationList.length > 0 && !isOpen) {
|
||||
// 当dom改变并且没有开启时,会自动开启
|
||||
setIsOpen(!isOpen);
|
||||
}
|
||||
};
|
||||
const observer = new MutationObserver(callback);
|
||||
observer.observe(target, config);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}
|
||||
}, [isOpen, allowToggleCollapsible]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
setOpen,
|
||||
}));
|
||||
|
||||
const setOpen = (innerIsOpen: boolean) => {
|
||||
setIsOpen(innerIsOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(className, s['content-block'])}
|
||||
style={style}
|
||||
ref={containerRef}
|
||||
>
|
||||
<header
|
||||
className={classNames(s['header-content'])}
|
||||
onClick={e => {
|
||||
if (!allowToggleCollapsible) {
|
||||
return;
|
||||
}
|
||||
// @danger 不可以阻止内部节点的点击冒泡,不然无法设置节点的选中态
|
||||
const el = e.target as HTMLElement;
|
||||
// 这里需要多重判断,
|
||||
// 第一次判断:如果包含在container内,才需要去切换open
|
||||
// 第二次判断:如果包含在action内,则不能切换open,其他都可以
|
||||
// @TIP contains方法会判断自身节点,即A.contains(A)也是true。但是这里就算是自身也没有影响
|
||||
if (containerRef.current && containerRef.current.contains(el)) {
|
||||
if (actionDivRef.current && actionDivRef.current.contains(el)) {
|
||||
// 此时不切换open
|
||||
return;
|
||||
}
|
||||
setIsOpen(!isOpen);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className={s.header}>
|
||||
{allowToggleCollapsible ? (
|
||||
<div
|
||||
className={classNames({
|
||||
[s['header-icon-arrow'] || '']: true,
|
||||
[s.open || '']: isOpen,
|
||||
})}
|
||||
>
|
||||
<IconArrowRight />
|
||||
</div>
|
||||
) : null}
|
||||
<div className={s.label}>{title}</div>
|
||||
{tooltip ? (
|
||||
<Tooltip
|
||||
showArrow
|
||||
position="top"
|
||||
className={s.popover}
|
||||
content={tooltip}
|
||||
>
|
||||
<IconInfo className={s.icon} />
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
<div ref={actionDivRef}>{actionButton}</div>
|
||||
</header>
|
||||
<div
|
||||
className={classNames({
|
||||
[s['overflow-content'] || '']: true,
|
||||
[contentClassName || '']: Boolean(contentClassName),
|
||||
[s.open || '']: isOpen,
|
||||
})}
|
||||
>
|
||||
<Collapsible keepDOM fade isOpen={isOpen}>
|
||||
<div
|
||||
className={s.content}
|
||||
ref={childNodeRef}
|
||||
style={{
|
||||
maxHeight: maxContentHeight ? maxContentHeight : undefined,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</Collapsible>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,34 @@
|
||||
.item {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
flex-shrink: 0;
|
||||
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.skills {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-wrap: wrap;
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 20px; // 142.857%
|
||||
color: var(--light-usage-bg-color-bg-0, #FFF);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { type PopoverProps } from '@coze-arch/bot-semi/Popover';
|
||||
import { Popover } from '@coze-arch/bot-semi';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
const POPOVER_PROPS: Partial<PopoverProps> = {
|
||||
style: {
|
||||
backgroundColor: 'var(--light-color-grey-grey-7, #41464C)',
|
||||
borderColor: 'var(--light-color-grey-grey-7, #41464C)',
|
||||
padding: '8px 12px',
|
||||
},
|
||||
showArrow: true,
|
||||
position: 'top',
|
||||
};
|
||||
|
||||
interface IProps {
|
||||
children: React.ReactNode;
|
||||
tooltip: React.ReactNode;
|
||||
icon: React.ReactElement;
|
||||
}
|
||||
|
||||
export const AgentSkillContent = React.memo((props: IProps) => {
|
||||
const { children, tooltip, icon } = props;
|
||||
|
||||
const iconNode = React.cloneElement(icon, {
|
||||
className: classnames(icon?.props?.className, styles.icon),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.item}>
|
||||
<Popover
|
||||
{...POPOVER_PROPS}
|
||||
content={<span className={styles['popover-content']}>{tooltip}</span>}
|
||||
>
|
||||
{iconNode}
|
||||
</Popover>
|
||||
<div className={styles.skills}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
// eslint-disable-next-line @coze-arch/no-pkg-dir-import
|
||||
import { type AgentModalTabKey } from '@coze-agent-ide/tool-config/src/types';
|
||||
import { AbilityScope } from '@coze-agent-ide/tool-config';
|
||||
import { UITabsModal } from '@coze-arch/bot-semi';
|
||||
import { type ModalProps } from '@douyinfe/semi-foundation/lib/es/modal/modalFoundation';
|
||||
|
||||
import { ToolContainer } from '../tool-container';
|
||||
import { useAgentModalTriggerEvent } from '../../hooks/agent-skill-modal/use-agent-modal-trigger-event';
|
||||
|
||||
export interface IAgentSkillModalPane {
|
||||
key: AgentModalTabKey;
|
||||
tab: React.ReactNode;
|
||||
pane: React.ReactNode;
|
||||
}
|
||||
|
||||
interface AgentSkillModalProps extends Partial<ModalProps> {
|
||||
tabPanes: IAgentSkillModalPane[];
|
||||
}
|
||||
|
||||
export const AgentSkillModal: FC<AgentSkillModalProps> = ({
|
||||
tabPanes,
|
||||
...restModalProps
|
||||
}) => {
|
||||
const { emitTabChangeEvent } = useAgentModalTriggerEvent();
|
||||
return (
|
||||
<UITabsModal
|
||||
visible
|
||||
tabs={{
|
||||
tabsProps: {
|
||||
lazyRender: true,
|
||||
onChange: activityKey =>
|
||||
emitTabChangeEvent(activityKey as AgentModalTabKey),
|
||||
},
|
||||
tabPanes: tabPanes.map(tab => ({
|
||||
tabPaneProps: {
|
||||
tab: tab.tab,
|
||||
itemKey: tab.key,
|
||||
},
|
||||
content: (
|
||||
<ToolContainer scope={AbilityScope.AGENT_SKILL}>
|
||||
<>{tab.pane}</>
|
||||
</ToolContainer>
|
||||
),
|
||||
})),
|
||||
}}
|
||||
{...restModalProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
.container {
|
||||
margin-top: 8px;
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
overflow: hidden auto;
|
||||
width: 100%;
|
||||
max-height: 280px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 20px; // 142.857%
|
||||
color: var(--light-usage-text-color-text-3, rgb(29 28 35 / 35%));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 FC, type PropsWithChildren, Children, useEffect } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { AbilityScope } from '@coze-agent-ide/tool-config';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
|
||||
import { AgentSkillContentBlock } from '../agent-skill-content-block';
|
||||
import { AgentSkillContainer } from '../agent-skill-container';
|
||||
import { hasValidAgentSkillKey } from '../../utils/has-valid-key';
|
||||
import { useSubscribeToolStore } from '../../hooks/public/store/use-tool-store';
|
||||
import { useHasAgentSkill } from '../../hooks/public/agent/use-has-agent-skill';
|
||||
import { useRegisterAgentSkillKey } from '../../hooks/builtin/use-register-agent-skill-key';
|
||||
import { useNoneAgentSkill } from '../../hooks/agent-skill/use-agent-skill';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface IProps {
|
||||
title: string;
|
||||
agentId: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
actionButton?: React.ReactNode;
|
||||
emptyText: string;
|
||||
}
|
||||
|
||||
export const AgentSkillView: FC<PropsWithChildren<IProps>> = ({
|
||||
children,
|
||||
agentId,
|
||||
title,
|
||||
className,
|
||||
style,
|
||||
actionButton,
|
||||
emptyText,
|
||||
}) => {
|
||||
const readonly = useBotDetailIsReadonly();
|
||||
|
||||
const registerAgentSkillKey = useRegisterAgentSkillKey();
|
||||
const noneAgentSkill = useNoneAgentSkill();
|
||||
const { getHasAgentSkill } = useHasAgentSkill();
|
||||
|
||||
useSubscribeToolStore(AbilityScope.AGENT_SKILL, agentId);
|
||||
|
||||
// 前置注册
|
||||
useEffect(() => {
|
||||
Children.map(children, child => {
|
||||
if (!hasValidAgentSkillKey(child)) {
|
||||
return child;
|
||||
}
|
||||
|
||||
const agentSkillKey = child.key;
|
||||
|
||||
registerAgentSkillKey(agentSkillKey);
|
||||
});
|
||||
}, [children]);
|
||||
|
||||
return (
|
||||
<AgentSkillContentBlock
|
||||
title={title}
|
||||
className={classNames(styles.container, className)}
|
||||
style={style}
|
||||
actionButton={!readonly && actionButton}
|
||||
>
|
||||
{noneAgentSkill ? (
|
||||
<span className={styles.empty}>{emptyText}</span>
|
||||
) : (
|
||||
<div className={styles.content}>
|
||||
{Children.map(children, child => {
|
||||
if (
|
||||
typeof child === 'string' ||
|
||||
typeof child === 'number' ||
|
||||
typeof child === 'boolean'
|
||||
) {
|
||||
return child;
|
||||
}
|
||||
if (!hasValidAgentSkillKey(child)) {
|
||||
return child;
|
||||
}
|
||||
const agentSkillKey = child.key;
|
||||
const hasAgentSkill = getHasAgentSkill(agentSkillKey);
|
||||
return (
|
||||
hasAgentSkill && (
|
||||
<AgentSkillContainer agentSkillKey={agentSkillKey}>
|
||||
<>{child}</>
|
||||
</AgentSkillContainer>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</AgentSkillContentBlock>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { IconButton } from '@coze-arch/coze-design';
|
||||
import { IconAuto } from '@coze-arch/bot-icons';
|
||||
|
||||
import { ToolTooltip } from '../tool-tooltip';
|
||||
import { type ToolButtonCommonProps } from '../../typings/button';
|
||||
|
||||
interface AutoGenerateButtonProps extends ToolButtonCommonProps {
|
||||
enableAutoHidden?: boolean;
|
||||
}
|
||||
|
||||
export const AutoGenerateButton: FC<AutoGenerateButtonProps> = ({
|
||||
onClick,
|
||||
tooltips,
|
||||
loading,
|
||||
disabled,
|
||||
enableAutoHidden,
|
||||
...restProps
|
||||
}) => {
|
||||
const readonly = useBotDetailIsReadonly();
|
||||
|
||||
if (readonly && enableAutoHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ToolTooltip content={tooltips}>
|
||||
<IconButton
|
||||
icon={<IconAuto />}
|
||||
loading={loading}
|
||||
disabled={!!disabled}
|
||||
onClick={onClick}
|
||||
size="small"
|
||||
color="secondary"
|
||||
data-testid={restProps['data-testid']}
|
||||
/>
|
||||
</ToolTooltip>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
.tool-container-fallback {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin-bottom: 4px;
|
||||
padding: 0 3px;
|
||||
|
||||
color: #F93920;
|
||||
|
||||
border-bottom: 1px solid;
|
||||
|
||||
@apply coz-stroke-primary;
|
||||
|
||||
}
|
||||
|
||||
.text {
|
||||
margin-left: 7px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 FC, useState } from 'react';
|
||||
|
||||
import { getSlardarInstance } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconInfoCircle } from '@coze-arch/bot-icons';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface IProps {
|
||||
toolTitle?: string;
|
||||
}
|
||||
export const ToolContainerFallback: FC<IProps> = ({ toolTitle }) => {
|
||||
const [sessionId] = useState(() => getSlardarInstance()?.config()?.sessionId);
|
||||
|
||||
return (
|
||||
<div className={styles['tool-container-fallback']}>
|
||||
<IconInfoCircle />
|
||||
<span className={styles.text}>
|
||||
{toolTitle}
|
||||
{I18n.t('tool_load_error')}
|
||||
</span>
|
||||
{!!sessionId && (
|
||||
<div className="leading-[12px] ml-[6px] text-[12px] text-gray-400">
|
||||
{sessionId}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
.wrapper {
|
||||
padding-bottom: 24px;
|
||||
|
||||
&.left {
|
||||
.header {
|
||||
padding: 0 28px 6px;
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
.header {
|
||||
height: 22px;
|
||||
padding: 0 8px 6px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: none;
|
||||
|
||||
.title {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.action-nodes {}
|
||||
}
|
||||
|
||||
:global {
|
||||
.collapse-panel-hide-underline > div {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.display-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// // 第一个容器不加顶边
|
||||
:nth-child(1 of.wrapper) {
|
||||
.header {
|
||||
margin-top: 0;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 FC, type ReactNode } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { isArray } from 'lodash-es';
|
||||
import classnames from 'classnames';
|
||||
import {
|
||||
TOOL_KEY_TO_API_STATUS_KEY_MAP,
|
||||
type ToolGroupKey,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { useLayoutContext } from '@coze-arch/bot-hooks';
|
||||
import { TabStatus } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { useRegisteredToolKeyConfigList } from '../../hooks/builtin/use-register-tool-key';
|
||||
import { usePreference } from '../../context/preference-context';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
/**
|
||||
* 分组容器
|
||||
* @see
|
||||
*/
|
||||
|
||||
interface IProps {
|
||||
children?: ReactNode;
|
||||
title: ReactNode;
|
||||
toolGroupKey?: ToolGroupKey;
|
||||
actionNodes?: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const GroupingContainer: FC<IProps> = props => {
|
||||
const { children, title, toolGroupKey, actionNodes, className } = props;
|
||||
// 容器在页面中的展示位置,不同位置样式有区别
|
||||
const { placement } = useLayoutContext();
|
||||
|
||||
const { isReadonly } = usePreference();
|
||||
|
||||
const registeredToolKeyConfigList = useRegisteredToolKeyConfigList();
|
||||
|
||||
const registeredToolKeyListInGroup = registeredToolKeyConfigList.filter(
|
||||
toolConfig => toolConfig.toolGroupKey === toolGroupKey,
|
||||
);
|
||||
|
||||
const statusKeys = registeredToolKeyListInGroup.map(
|
||||
toolConfig => TOOL_KEY_TO_API_STATUS_KEY_MAP[toolConfig.toolKey],
|
||||
);
|
||||
|
||||
const { enableToolHiddenMode } = usePreference();
|
||||
|
||||
const tabInvisible = usePageRuntimeStore(
|
||||
useShallow(state =>
|
||||
statusKeys
|
||||
.map(_key => state.botSkillBlockCollapsibleState[_key])
|
||||
.every(status => status === TabStatus.Hide),
|
||||
),
|
||||
);
|
||||
|
||||
const getInvisible = () => {
|
||||
if (!enableToolHiddenMode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isReadonly) {
|
||||
return !registeredToolKeyListInGroup.some(
|
||||
toolConfig => toolConfig.hasValidData,
|
||||
);
|
||||
}
|
||||
|
||||
return tabInvisible;
|
||||
};
|
||||
|
||||
const invisible = getInvisible();
|
||||
|
||||
if (!children || (isArray(children) && !children.length)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(styles[placement], 'coz-bg-plus', className, {
|
||||
hidden: invisible,
|
||||
[styles.wrapper || '']: !invisible,
|
||||
})}
|
||||
>
|
||||
<div className={styles.header}>
|
||||
<div className={classnames(styles.title, 'coz-fg-secondary')}>
|
||||
{title}
|
||||
</div>
|
||||
<div className={styles['action-nodes']}>{actionNodes}</div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 { useEffect, type FC } from 'react';
|
||||
|
||||
import { useIsAllToolHidden } from '../../hooks/public/container/use-tool-all-hidden';
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
type IProps = Record<string, unknown>;
|
||||
|
||||
export const InvisibleToolController: FC<IProps> = () => {
|
||||
const isAllToolHidden = useIsAllToolHidden();
|
||||
|
||||
const { eventCallbacks, store } = useAbilityAreaContext();
|
||||
const { isInitialed } = store.useToolAreaStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isInitialed) {
|
||||
return;
|
||||
}
|
||||
eventCallbacks?.onAllToolHiddenStatusChange?.(isAllToolHidden);
|
||||
}, [isAllToolHidden, isInitialed]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { ToolGroupKey } from '@coze-agent-ide/tool-config';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
ModelFuncConfigStatus,
|
||||
ModelFuncConfigType,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { useBotSkillStore } from '@coze-studio/bot-detail-store/bot-skill';
|
||||
import {
|
||||
mergeModelFuncConfigStatus,
|
||||
useModelCapabilityConfig,
|
||||
} from '@coze-agent-ide/bot-editor-context-store';
|
||||
import { IconCozWarningCircleFillPalette } from '@coze-arch/coze-design/icons';
|
||||
import { Tag, Tooltip } from '@coze-arch/coze-design';
|
||||
|
||||
import { abilityKey2ModelFunctionConfigType } from '../../utils/model-function-config-type-mapping';
|
||||
import { useGetToolConfig } from '../../hooks/builtin/use-get-tool-config';
|
||||
import { useAbilityConfig } from '../../hooks/builtin/use-ability-config';
|
||||
|
||||
export const TipsDisplay: FC<{
|
||||
status?: ModelFuncConfigStatus;
|
||||
modelName: string;
|
||||
showTooltip?: boolean;
|
||||
toolName?: string;
|
||||
className?: string;
|
||||
}> = ({
|
||||
status = ModelFuncConfigStatus.FullSupport,
|
||||
modelName,
|
||||
toolName,
|
||||
showTooltip = true,
|
||||
className,
|
||||
}) => {
|
||||
if (status === ModelFuncConfigStatus.NotSupport) {
|
||||
const content = (
|
||||
<Tag
|
||||
size="mini"
|
||||
color="primary"
|
||||
className={classNames('mx-2', className)}
|
||||
prefixIcon={
|
||||
<IconCozWarningCircleFillPalette className="coz-fg-hglt-red" />
|
||||
}
|
||||
>
|
||||
{I18n.t('not_supported')}
|
||||
</Tag>
|
||||
);
|
||||
if (!showTooltip) {
|
||||
return content;
|
||||
}
|
||||
return (
|
||||
<Tooltip
|
||||
content={
|
||||
toolName
|
||||
? I18n.t('not_supported_explain_toolName', {
|
||||
modelName,
|
||||
toolName,
|
||||
})
|
||||
: I18n.t('not_supported_explain', { modelName })
|
||||
}
|
||||
>
|
||||
{content}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
if (status === ModelFuncConfigStatus.PoorSupport) {
|
||||
const content = (
|
||||
<Tag
|
||||
size="mini"
|
||||
color="primary"
|
||||
className={classNames('mx-2', className)}
|
||||
prefixIcon={
|
||||
<IconCozWarningCircleFillPalette className="coz-fg-hglt-yellow" />
|
||||
}
|
||||
>
|
||||
{I18n.t('support_poor')}
|
||||
</Tag>
|
||||
);
|
||||
if (!showTooltip) {
|
||||
return content;
|
||||
}
|
||||
return (
|
||||
<Tooltip
|
||||
content={
|
||||
toolName
|
||||
? I18n.t('poorly_supported_explain_toolName', {
|
||||
modelName,
|
||||
toolName,
|
||||
})
|
||||
: I18n.t('support_poor_explain', { modelName })
|
||||
}
|
||||
>
|
||||
{content}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const TipsImpl: FC<{ configType: ModelFuncConfigType }> = ({ configType }) => {
|
||||
const modelCapabilityConfig = useModelCapabilityConfig();
|
||||
const [configStatus, modelName] = modelCapabilityConfig[configType];
|
||||
return <TipsDisplay status={configStatus} modelName={modelName} />;
|
||||
};
|
||||
|
||||
const TipsImplForKnowledge: FC<{
|
||||
configType: ModelFuncConfigType;
|
||||
toolName: string;
|
||||
}> = ({ configType, toolName }) => {
|
||||
const modelCapabilityConfig = useModelCapabilityConfig();
|
||||
const auto = useBotSkillStore(state => state.knowledge.dataSetInfo.auto);
|
||||
const [autoConfigStatus, autoModelName] =
|
||||
modelCapabilityConfig[
|
||||
auto
|
||||
? ModelFuncConfigType.KnowledgeAutoCall
|
||||
: ModelFuncConfigType.KnowledgeOnDemandCall
|
||||
];
|
||||
// 根据自动调用还是按需调用,获取另一个 status,取合并
|
||||
const [configStatus, modelName] = modelCapabilityConfig[configType];
|
||||
const mergedStatus = mergeModelFuncConfigStatus(
|
||||
autoConfigStatus,
|
||||
configStatus,
|
||||
);
|
||||
const mergedToolTittle: string[] = [];
|
||||
if (mergedStatus === configStatus) {
|
||||
mergedToolTittle.push(toolName);
|
||||
}
|
||||
if (mergedStatus === autoConfigStatus) {
|
||||
mergedToolTittle.push(
|
||||
auto
|
||||
? I18n.t('dataset_automatic_call')
|
||||
: I18n.t('dataset_on_demand_call'),
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TipsDisplay
|
||||
status={mergedStatus}
|
||||
modelName={mergedStatus === autoConfigStatus ? autoModelName : modelName}
|
||||
// 因为按需调用的提示合并到了这里,知识库显示 tips 时,需要显示具体不支持的能力(按需调用 / 知识库)
|
||||
toolName={mergedToolTittle.join(', ')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ModelCapabilityTipsImpl = () => {
|
||||
const { abilityKey } = useAbilityConfig();
|
||||
const getToolConfig = useGetToolConfig();
|
||||
const toolConfig = getToolConfig(abilityKey);
|
||||
|
||||
const configType = abilityKey
|
||||
? abilityKey2ModelFunctionConfigType(abilityKey)
|
||||
: undefined;
|
||||
|
||||
// 降低 useModelCapabilityConfig 调用频率
|
||||
if (toolConfig && configType) {
|
||||
// 知识库需要引入一个额外的判断是否是按需调用
|
||||
if (toolConfig.toolGroupKey === ToolGroupKey.KNOWLEDGE) {
|
||||
return (
|
||||
<TipsImplForKnowledge
|
||||
configType={configType}
|
||||
toolName={toolConfig.toolTitle}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <TipsImpl configType={configType} />;
|
||||
}
|
||||
// 不需要渲染任何内容
|
||||
return null;
|
||||
};
|
||||
|
||||
export const ModelCapabilityTips = ModelCapabilityTipsImpl;
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 FC, type PropsWithChildren } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
AbilityScope,
|
||||
TOOL_KEY_TO_API_STATUS_KEY_MAP,
|
||||
type ToolKey,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { ErrorBoundary } from '@coze-arch/logger';
|
||||
import { TabStatus } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { ToolContainerFallback } from '../fallbacks';
|
||||
import { useGetToolConfig } from '../../hooks/builtin/use-get-tool-config';
|
||||
import { usePreference } from '../../context/preference-context';
|
||||
import { AbilityConfigContextProvider } from '../../context/ability-config-context';
|
||||
|
||||
interface IProps {
|
||||
scope: AbilityScope;
|
||||
toolKey?: ToolKey;
|
||||
onMouseOver?: (toolKey: string | undefined) => void;
|
||||
onMouseLeave?: (toolKey: string | undefined) => void;
|
||||
}
|
||||
|
||||
export const ToolContainer: FC<PropsWithChildren<IProps>> = ({
|
||||
children,
|
||||
toolKey,
|
||||
onMouseOver,
|
||||
onMouseLeave,
|
||||
}) => {
|
||||
const { enableToolHiddenMode, isReadonly } = usePreference();
|
||||
|
||||
const toolStatus = usePageRuntimeStore(state =>
|
||||
toolKey
|
||||
? state.botSkillBlockCollapsibleState[
|
||||
TOOL_KEY_TO_API_STATUS_KEY_MAP[toolKey]
|
||||
]
|
||||
: null,
|
||||
);
|
||||
|
||||
const getToolConfig = useGetToolConfig();
|
||||
|
||||
const toolConfig = getToolConfig(toolKey);
|
||||
|
||||
const getInvisible = () => {
|
||||
if (!enableToolHiddenMode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isReadonly) {
|
||||
return !toolConfig?.hasValidData;
|
||||
}
|
||||
|
||||
return toolStatus === TabStatus.Hide;
|
||||
};
|
||||
|
||||
const invisible = getInvisible();
|
||||
|
||||
const handleOnMouseEnter = (key: string) => {
|
||||
const siblingClassList = document.querySelector(`.collapse-panel-${key}`)
|
||||
?.previousElementSibling?.classList;
|
||||
// 如果找到兄弟节点则隐藏下划线
|
||||
if (siblingClassList?.contains('collapse-panel')) {
|
||||
siblingClassList.add('collapse-panel-hide-underline');
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnMouseLeave = () => {
|
||||
const className = 'collapse-panel-hide-underline';
|
||||
document
|
||||
.querySelectorAll(`.${className}`)
|
||||
.forEach(element => element.classList.remove(className));
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
hidden: invisible,
|
||||
'collapse-panel': true,
|
||||
[`collapse-panel-${toolKey}`]: true,
|
||||
})}
|
||||
onMouseEnter={() => {
|
||||
if (toolKey) {
|
||||
handleOnMouseEnter(toolKey);
|
||||
}
|
||||
}}
|
||||
onMouseLeave={handleOnMouseLeave}
|
||||
>
|
||||
<ErrorBoundary
|
||||
errorBoundaryName={`botEditorTool${toolConfig?.toolKey}`}
|
||||
FallbackComponent={() => (
|
||||
<ToolContainerFallback toolTitle={toolConfig?.toolTitle} />
|
||||
)}
|
||||
>
|
||||
<AbilityConfigContextProvider
|
||||
abilityKey={toolKey}
|
||||
scope={AbilityScope.TOOL}
|
||||
>
|
||||
{children}
|
||||
</AbilityConfigContextProvider>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,162 @@
|
||||
@common-box-shadow: 0px 2px 8px 0px rgba(31, 35, 41, 0.02),
|
||||
0px 2px 4px 0px rgba(31, 35, 41, 0.02), 0px 2px 2px 0px rgba(31, 35, 41, 0.02);
|
||||
|
||||
.common-svg-icon(@size: 14px) {
|
||||
>svg {
|
||||
width: @size;
|
||||
height: @size;
|
||||
|
||||
@apply coz-fg-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.content-block {
|
||||
width: 100%;
|
||||
// border-radius: 8px;
|
||||
// background-color: #fff;
|
||||
// box-shadow: (@common-box-shadow);
|
||||
// margin-bottom: 4px;
|
||||
border-bottom: 1px solid theme('colors.stroke.5');
|
||||
|
||||
&.isOpen {
|
||||
border-bottom: 1px solid theme('colors.stroke.5') !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
&.left {
|
||||
.header-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.content-old {
|
||||
padding: 4px 28px;
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
.header-content {
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 4px 0 16px;
|
||||
}
|
||||
|
||||
.content-old {
|
||||
padding: 8px 8px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
&.collapsible {
|
||||
&:hover {
|
||||
@apply coz-mg-secondary-hovered;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply coz-mg-secondary-pressed;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply coz-fg-primary;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.header-icon-arrow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
margin-right: 8px;
|
||||
padding: 1px;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
:global {
|
||||
.semi-icon {
|
||||
svg {
|
||||
font-size: 14px;
|
||||
|
||||
@apply coz-fg-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
display: flex;
|
||||
margin-right: 8px;
|
||||
|
||||
>img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex: 1 1;
|
||||
align-items: center;
|
||||
|
||||
height: 100%;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
|
||||
|
||||
.icon {
|
||||
margin-left: 8px;
|
||||
.common-svg-icon(16px)
|
||||
}
|
||||
}
|
||||
|
||||
.action-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.setting {
|
||||
// margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
// border-top: 1px solid #efefef;
|
||||
overflow: auto;
|
||||
height: calc(100% - 48px);
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-collapsible-wrapper {
|
||||
padding-left: 0 !important;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.semi-button {
|
||||
svg {
|
||||
@apply coz-fg-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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 CSSProperties,
|
||||
type PropsWithChildren,
|
||||
type ReactNode,
|
||||
useImperativeHandle,
|
||||
useState,
|
||||
useEffect,
|
||||
useRef,
|
||||
useMemo,
|
||||
useCallback,
|
||||
type ForwardedRef,
|
||||
} from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { isBoolean } from 'lodash-es';
|
||||
import classNames from 'classnames';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { Collapsible } from '@coze-arch/coze-design';
|
||||
import {
|
||||
type OpenBlockEvent,
|
||||
handleEvent,
|
||||
removeEvent,
|
||||
skillKeyToApiStatusKeyTransformer,
|
||||
} from '@coze-arch/bot-utils';
|
||||
import { BotPageFromEnum } from '@coze-arch/bot-typings/common';
|
||||
import { Image } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
IconInfo,
|
||||
IconChevronRight,
|
||||
IconChevronDown,
|
||||
} from '@coze-arch/bot-icons';
|
||||
import { useLayoutContext } from '@coze-arch/bot-hooks';
|
||||
import { TabStatus } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { ToolTooltip } from '../tool-tooltip';
|
||||
import { ToolPopover } from '../tool-popover';
|
||||
import { ModelCapabilityTips } from '../model-capability-tips';
|
||||
import { toolKeyToApiStatusKeyTransformer } from '../../utils/tool-content-block';
|
||||
import { EventCenterEventName } from '../../typings/scoped-events';
|
||||
import { type IToggleContentBlockEventParams } from '../../typings/event';
|
||||
import { useRegisterCollapse } from '../../hooks/tool/use-tool-toggle-collapse';
|
||||
import { useEvent } from '../../hooks/event/use-event';
|
||||
import { useAbilityConfig } from '../../hooks/builtin/use-ability-config';
|
||||
import { openBlockEventToToolKey } from '../../constants/tool-content-block';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
interface ToolContentBlockProps {
|
||||
contentClassName?: string;
|
||||
header?: ReactNode;
|
||||
icon?: string;
|
||||
actionButton?: ReactNode;
|
||||
tooltip?: ReactNode;
|
||||
setting?: ReactNode;
|
||||
maxContentHeight?: number;
|
||||
showBottomBorder?: boolean;
|
||||
showBorderTopRadius?: boolean;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
collapsible?: boolean;
|
||||
defaultExpand?: boolean;
|
||||
onRef?: ForwardedRef<ToolContentRef>;
|
||||
/**
|
||||
* @deprecated tool 插件化改造后无需传入 (如果保留老式event则需要传入)
|
||||
*/
|
||||
blockEventName?: OpenBlockEvent;
|
||||
tooltipType?: 'tooltip' | 'popOver';
|
||||
childNodeWrapClassName?: string;
|
||||
headerClassName?: string;
|
||||
}
|
||||
|
||||
interface ToolContentRef {
|
||||
setOpen?: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
/* eslint @coze-arch/max-line-per-function: ["error", {"max": 250}] */
|
||||
export const ToolContentBlock: React.FC<
|
||||
PropsWithChildren<ToolContentBlockProps>
|
||||
> = ({
|
||||
children,
|
||||
icon,
|
||||
header,
|
||||
actionButton,
|
||||
maxContentHeight,
|
||||
tooltip,
|
||||
tooltipType = 'popOver',
|
||||
setting,
|
||||
className,
|
||||
style,
|
||||
collapsible = true,
|
||||
defaultExpand,
|
||||
onRef,
|
||||
blockEventName,
|
||||
childNodeWrapClassName,
|
||||
headerClassName,
|
||||
}) => {
|
||||
/** 后续长期使用的ToolKey */
|
||||
const { abilityKey } = useAbilityConfig();
|
||||
|
||||
const { registerCollapse } = useRegisterCollapse();
|
||||
|
||||
useEffect(() => {
|
||||
if (!abilityKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
return registerCollapse(isExpand => setIsOpen(isExpand), abilityKey);
|
||||
}, [abilityKey]);
|
||||
|
||||
const isReadonly = useBotDetailIsReadonly();
|
||||
const { botId } = useBotInfoStore(
|
||||
useShallow(store => ({
|
||||
botId: store.botId,
|
||||
})),
|
||||
);
|
||||
const { editable, setBotSkillBlockCollapsibleState } = usePageRuntimeStore(
|
||||
useShallow(store => ({
|
||||
editable: store.editable,
|
||||
setBotSkillBlockCollapsibleState: store.setBotSkillBlockCollapsibleState,
|
||||
})),
|
||||
);
|
||||
|
||||
// 容器在页面中的展示位置,不同位置样式有区别
|
||||
const { placement } = useLayoutContext();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const initialized = useRef<boolean>(false);
|
||||
const childNode = (
|
||||
<div
|
||||
className={classNames(s.content, childNodeWrapClassName)}
|
||||
style={{ maxHeight: maxContentHeight ? maxContentHeight : 'unset' }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
const setOpen = ($isOpen: boolean) => {
|
||||
setIsOpen($isOpen);
|
||||
// 记录用户使用状态
|
||||
if (editable && !isReadonly && (abilityKey || blockEventName)) {
|
||||
if (blockEventName) {
|
||||
const blockKey = openBlockEventToToolKey[blockEventName];
|
||||
|
||||
blockKey &&
|
||||
setBotSkillBlockCollapsibleState({
|
||||
[skillKeyToApiStatusKeyTransformer(blockKey)]: $isOpen
|
||||
? TabStatus.Open
|
||||
: TabStatus.Close,
|
||||
});
|
||||
} else if (abilityKey) {
|
||||
setBotSkillBlockCollapsibleState({
|
||||
[toolKeyToApiStatusKeyTransformer(abilityKey)]: $isOpen
|
||||
? TabStatus.Open
|
||||
: TabStatus.Close,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 尚未完成初始化时如果用户手动展开/收起,则马上完成初始化
|
||||
if (!initialized.current) {
|
||||
initialized.current = true;
|
||||
}
|
||||
};
|
||||
useImperativeHandle(onRef, () => ({
|
||||
setOpen,
|
||||
}));
|
||||
|
||||
const onEvent = useCallback(() => {
|
||||
setOpen(true);
|
||||
}, [
|
||||
blockEventName,
|
||||
botId,
|
||||
editable,
|
||||
isReadonly,
|
||||
openBlockEventToToolKey,
|
||||
abilityKey,
|
||||
]);
|
||||
|
||||
const onEventNew = useCallback(
|
||||
({ abilityKey: _abilityKey, isExpand }: IToggleContentBlockEventParams) => {
|
||||
if (_abilityKey === abilityKey) {
|
||||
setOpen(isExpand);
|
||||
}
|
||||
},
|
||||
[abilityKey, setOpen],
|
||||
);
|
||||
|
||||
const { on } = useEvent();
|
||||
|
||||
useEffect(() => {
|
||||
blockEventName && handleEvent(blockEventName, onEvent);
|
||||
const offEvent =
|
||||
abilityKey &&
|
||||
on<IToggleContentBlockEventParams>(
|
||||
EventCenterEventName.ToggleContentBlock,
|
||||
onEventNew,
|
||||
);
|
||||
return () => {
|
||||
blockEventName && removeEvent(blockEventName, onEvent);
|
||||
offEvent?.();
|
||||
};
|
||||
}, [onEvent]);
|
||||
|
||||
useEffect(() => {
|
||||
// 传入默认值之后才能初始化
|
||||
if (isBoolean(defaultExpand)) {
|
||||
// 初始化完成后忽略 defaultExpand 变化
|
||||
if (!initialized.current) {
|
||||
setIsOpen(defaultExpand);
|
||||
initialized.current = true;
|
||||
}
|
||||
} else {
|
||||
setIsOpen(false);
|
||||
initialized.current = false;
|
||||
}
|
||||
}, [defaultExpand]);
|
||||
|
||||
const content = useMemo(() => {
|
||||
// 初始化成功之后才能开始渲染 Collapsible 组件
|
||||
if (!initialized.current) {
|
||||
return null;
|
||||
}
|
||||
if (collapsible) {
|
||||
return (
|
||||
<Collapsible keepDOM isOpen={isOpen || !collapsible}>
|
||||
{childNode}
|
||||
</Collapsible>
|
||||
);
|
||||
} else {
|
||||
return childNode;
|
||||
}
|
||||
}, [collapsible, isOpen, childNode]);
|
||||
|
||||
const onToggle = () => {
|
||||
if (collapsible) {
|
||||
setOpen(!isOpen);
|
||||
}
|
||||
};
|
||||
|
||||
const isFromStore = usePageRuntimeStore(
|
||||
state => state.pageFrom === BotPageFromEnum.Store,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
s['content-block'],
|
||||
s[placement],
|
||||
{
|
||||
[s.isOpen || '']: isOpen,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
<header
|
||||
className={classNames(s['header-content'], headerClassName, {
|
||||
[s.collapsible || '']: collapsible,
|
||||
})}
|
||||
>
|
||||
<div className={s.header} onClick={onToggle}>
|
||||
{collapsible ? (
|
||||
<div className={s['header-icon-arrow']}>
|
||||
{isOpen ? <IconChevronDown /> : <IconChevronRight />}
|
||||
</div>
|
||||
) : null}
|
||||
{icon ? (
|
||||
<Image preview={false} className={s['header-icon']} src={icon} />
|
||||
) : null}
|
||||
<div className="shrink-0">{header}</div>
|
||||
{tooltip && tooltipType === 'popOver' ? (
|
||||
<ToolPopover
|
||||
content={<div onClick={e => e.stopPropagation()}>{tooltip}</div>}
|
||||
>
|
||||
<IconInfo className={s.icon} />
|
||||
</ToolPopover>
|
||||
) : null}
|
||||
{tooltip && tooltipType === 'tooltip' ? (
|
||||
<ToolTooltip content={<div>{tooltip}</div>}>
|
||||
<IconInfo className={s.icon} />
|
||||
</ToolTooltip>
|
||||
) : null}
|
||||
{!isFromStore ? <ModelCapabilityTips /> : null}
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
s['action-button'],
|
||||
'grid grid-flow-row gap-x-[2px]',
|
||||
)}
|
||||
>
|
||||
{!!setting && <div className={s.setting}>{setting}</div>}
|
||||
{actionButton}
|
||||
</div>
|
||||
</header>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 ComponentProps, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozCardPencil } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemAction } from '..';
|
||||
|
||||
type ToolItemActionCardProps = ComponentProps<typeof ToolItemAction>;
|
||||
|
||||
export const ToolItemActionCard: FC<ToolItemActionCardProps> = props => {
|
||||
const { disabled } = props;
|
||||
|
||||
return (
|
||||
<ToolItemAction {...props}>
|
||||
<IconCozCardPencil
|
||||
className={classNames('text-sm', {
|
||||
'coz-fg-secondary': !disabled,
|
||||
'coz-fg-dim': disabled,
|
||||
})}
|
||||
/>
|
||||
</ToolItemAction>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 ComponentProps, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozCopy } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemAction } from '..';
|
||||
|
||||
type ToolItemActionCopyProps = ComponentProps<typeof ToolItemAction>;
|
||||
|
||||
export const ToolItemActionCopy: FC<ToolItemActionCopyProps> = props => {
|
||||
const { disabled } = props;
|
||||
return (
|
||||
<ToolItemAction {...props}>
|
||||
<IconCozCopy
|
||||
className={classNames('text-sm', {
|
||||
'coz-fg-secondary': !disabled,
|
||||
'coz-fg-dim': disabled,
|
||||
})}
|
||||
/>
|
||||
</ToolItemAction>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 ComponentProps, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozTrashCan } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemAction } from '..';
|
||||
|
||||
type ToolItemActionDeleteProps = ComponentProps<typeof ToolItemAction>;
|
||||
|
||||
export const ToolItemActionDelete: FC<ToolItemActionDeleteProps> = props => {
|
||||
const { disabled } = props;
|
||||
return (
|
||||
<ToolItemAction {...props}>
|
||||
<IconCozTrashCan
|
||||
className={classNames('text-sm', {
|
||||
'coz-fg-secondary': !disabled,
|
||||
'coz-fg-dim': disabled,
|
||||
})}
|
||||
/>
|
||||
</ToolItemAction>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 ComponentProps, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozHamburger } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemAction } from '..';
|
||||
|
||||
type ToolItemActionEditProps = ComponentProps<typeof ToolItemAction> & {
|
||||
isDragging: boolean;
|
||||
};
|
||||
|
||||
export const ToolItemActionDrag: FC<ToolItemActionEditProps> = props => {
|
||||
const { disabled, isDragging } = props;
|
||||
return (
|
||||
<ToolItemAction hoverStyle={false} {...props}>
|
||||
<IconCozHamburger
|
||||
className={classNames('text-sm', {
|
||||
'coz-fg-secondary': !disabled,
|
||||
'coz-fg-dim': disabled,
|
||||
'cursor-grab': !isDragging,
|
||||
'cursor-grabbing': isDragging,
|
||||
})}
|
||||
/>
|
||||
</ToolItemAction>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 ComponentProps, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozEdit } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemAction } from '..';
|
||||
|
||||
type ToolItemActionEditProps = ComponentProps<typeof ToolItemAction>;
|
||||
|
||||
export const ToolItemActionEdit: FC<ToolItemActionEditProps> = props => {
|
||||
const { disabled } = props;
|
||||
return (
|
||||
<ToolItemAction {...props}>
|
||||
<IconCozEdit
|
||||
className={classNames('text-sm', {
|
||||
'coz-fg-secondary': !disabled,
|
||||
'coz-fg-dim': disabled,
|
||||
})}
|
||||
/>
|
||||
</ToolItemAction>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 ComponentProps, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemAction } from '..';
|
||||
|
||||
type ToolItemActionInfoProps = ComponentProps<typeof ToolItemAction>;
|
||||
|
||||
export const ToolItemActionInfo: FC<ToolItemActionInfoProps> = props => {
|
||||
const { disabled } = props;
|
||||
|
||||
return (
|
||||
<ToolItemAction {...props}>
|
||||
<IconCozInfoCircle
|
||||
className={classNames('text-sm', {
|
||||
'coz-fg-secondary': !disabled,
|
||||
'coz-fg-dim': disabled,
|
||||
})}
|
||||
/>
|
||||
</ToolItemAction>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 ComponentProps, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozSetting } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemAction } from '..';
|
||||
|
||||
type ToolItemActionSettingProps = ComponentProps<typeof ToolItemAction>;
|
||||
|
||||
export const ToolItemActionSetting: FC<ToolItemActionSettingProps> = props => {
|
||||
const { disabled } = props;
|
||||
return (
|
||||
<ToolItemAction {...props}>
|
||||
<IconCozSetting
|
||||
className={classNames('text-sm', {
|
||||
'coz-fg-secondary': !disabled,
|
||||
'coz-fg-dim': disabled,
|
||||
})}
|
||||
/>
|
||||
</ToolItemAction>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 FC, type PropsWithChildren, type MouseEventHandler } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { ToolTooltip } from '../tool-tooltip';
|
||||
import { type ToolButtonCommonProps } from '../../typings/button';
|
||||
|
||||
type ToolItemActionProps = ToolButtonCommonProps & {
|
||||
/** 是否展示hover样式 **/
|
||||
hoverStyle?: boolean;
|
||||
};
|
||||
|
||||
export const ToolItemAction: FC<PropsWithChildren<ToolItemActionProps>> = ({
|
||||
children,
|
||||
disabled,
|
||||
tooltips,
|
||||
onClick,
|
||||
hoverStyle = true,
|
||||
...restProps
|
||||
}) => {
|
||||
const handleClick: MouseEventHandler<HTMLDivElement> = e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onClick?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<ToolTooltip content={tooltips} disableFocusListener={disabled}>
|
||||
<div
|
||||
className={classNames(
|
||||
'w-[24px] h-[24px] flex justify-center items-center rounded-mini',
|
||||
{
|
||||
'hover:coz-mg-secondary-hovered active:coz-mg-secondary-pressed cursor-pointer':
|
||||
!disabled && hoverStyle,
|
||||
},
|
||||
{
|
||||
'coz-fg-dim hover:coz-fg-dim active:coz-fg-dim cursor-not-allowed':
|
||||
disabled,
|
||||
},
|
||||
)}
|
||||
onClick={disabled ? undefined : handleClick}
|
||||
data-testid={restProps['data-testid']}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</ToolTooltip>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozCard } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemIcon } from '..';
|
||||
|
||||
interface ToolItemIconCardProps {
|
||||
isError?: boolean;
|
||||
}
|
||||
|
||||
export const ToolItemIconCard: FC<ToolItemIconCardProps> = ({ isError }) => (
|
||||
<ToolItemIcon>
|
||||
<IconCozCard
|
||||
className={classNames('text-base', {
|
||||
'coz-fg-secondary': !isError,
|
||||
'coz-fg-hglt-yellow': isError,
|
||||
})}
|
||||
/>
|
||||
</ToolItemIcon>
|
||||
);
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemIcon } from '..';
|
||||
|
||||
export const ToolItemIconInfo: FC = () => (
|
||||
<ToolItemIcon>
|
||||
<IconCozInfoCircle className="text-sm coz-fg-secondary" />
|
||||
</ToolItemIcon>
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { IconCozPeople } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { ToolItemIcon } from '..';
|
||||
|
||||
export const ToolItemIconPeople = () => (
|
||||
<ToolItemIcon size="small">
|
||||
<IconCozPeople className="text-base coz-fg-secondary" />
|
||||
</ToolItemIcon>
|
||||
);
|
||||
@@ -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 FC, type PropsWithChildren } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
export const ToolItemIcon: FC<PropsWithChildren & { size?: 'small' }> = ({
|
||||
children,
|
||||
size,
|
||||
}) => (
|
||||
<div
|
||||
className={classNames('flex justify-center items-center cursor-pointer', {
|
||||
'w-[24px] h-[24px]': size !== 'small',
|
||||
'w-[16px] h-[16px]': size === 'small',
|
||||
})}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 FC, type PropsWithChildren } from 'react';
|
||||
|
||||
export const ToolItemList: FC<PropsWithChildren> = ({ children }) => (
|
||||
<div className="grid grid-flow-row gap-y-[4px]">{children}</div>
|
||||
);
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type ReactNode, type FC, type ChangeEvent } from 'react';
|
||||
|
||||
import { Switch } from '@coze-arch/coze-design';
|
||||
|
||||
import { ToolTooltip } from '../tool-tooltip';
|
||||
import { ToolItemIconInfo } from '../tool-item-icon/icons/tool-item-icon-info';
|
||||
|
||||
interface ToolItemSwitchProps {
|
||||
title: string;
|
||||
tooltips?: ReactNode;
|
||||
checked?: boolean;
|
||||
disabled?: boolean;
|
||||
onChange?:
|
||||
| ((checked: boolean, e: ChangeEvent<HTMLInputElement>) => void)
|
||||
| undefined;
|
||||
}
|
||||
|
||||
export const ToolItemSwitch: FC<ToolItemSwitchProps> = ({
|
||||
title,
|
||||
tooltips,
|
||||
checked,
|
||||
disabled,
|
||||
onChange,
|
||||
}) => (
|
||||
<div className="w-full px-[12px] py-[10px] coz-bg-max flex flex-row items-center rounded-[8px]">
|
||||
<div className="flex flex-row items-center flex-1 min-w-0">
|
||||
<p className="coz-fg-primary text-[14px] leading-[20px] mr-[4px]">
|
||||
{title}
|
||||
</p>
|
||||
<ToolTooltip content={tooltips}>
|
||||
<div>
|
||||
<ToolItemIconInfo />
|
||||
</div>
|
||||
</ToolTooltip>
|
||||
</div>
|
||||
<Switch
|
||||
size="mini"
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,3 @@
|
||||
.actions-large * svg {
|
||||
font-size: 16px;
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { type ReactNode, useRef, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useHover } from 'ahooks';
|
||||
import { Divider } from '@coze-arch/coze-design';
|
||||
|
||||
import { ToolTooltip } from '../tool-tooltip';
|
||||
import {
|
||||
ToolItemContextProvider,
|
||||
useToolItemContext,
|
||||
} from '../../context/tool-item-context';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
interface ToolItemProps {
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* tags
|
||||
*/
|
||||
tags?: ReactNode;
|
||||
/**
|
||||
* avatar
|
||||
*/
|
||||
avatar: string;
|
||||
/**
|
||||
* Actions区域
|
||||
*/
|
||||
actions?: ReactNode;
|
||||
/**
|
||||
* Icon展示区域
|
||||
*/
|
||||
icons?: ReactNode;
|
||||
/**
|
||||
* 禁用状态
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* tooltips
|
||||
*/
|
||||
tooltips?: ReactNode;
|
||||
/**
|
||||
* 点击卡片的回调
|
||||
*/
|
||||
onClick?: () => void;
|
||||
|
||||
// 尺寸 - 适配 workflow-as-agent 模式下的大号卡片
|
||||
size?: 'default' | 'large';
|
||||
|
||||
avatarStyle?: React.CSSProperties;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const _ToolItem: FC<ToolItemProps> = ({
|
||||
title,
|
||||
description,
|
||||
avatar,
|
||||
actions,
|
||||
icons,
|
||||
onClick,
|
||||
tooltips,
|
||||
tags,
|
||||
disabled,
|
||||
size = 'default',
|
||||
avatarStyle,
|
||||
}) => {
|
||||
const containerRef = useRef(null);
|
||||
const isHovering = useHover(containerRef);
|
||||
|
||||
const { isForceShowAction } = useToolItemContext();
|
||||
|
||||
const isShowAction = isHovering || isForceShowAction;
|
||||
|
||||
return (
|
||||
<ToolTooltip content={tooltips} position="top">
|
||||
<div
|
||||
data-testid={'bot.editor.tool.added-tool'}
|
||||
ref={containerRef}
|
||||
className={classNames(
|
||||
'w-full flex flex-row items-center coz-bg-max rounded-[8px]',
|
||||
{
|
||||
default: 'min-h-[56px] px-[8px] py-[10px]',
|
||||
large: 'min-h-[102px] px-[24px] py-[16px]',
|
||||
}[size],
|
||||
{
|
||||
'!coz-mg-secondary-hovered': isHovering,
|
||||
'cursor-pointer': Boolean(onClick),
|
||||
'cursor-default': !onClick,
|
||||
'cursor-not-allowed': disabled,
|
||||
},
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-row flex-1 min-w-[0px] justify-center items-center',
|
||||
{
|
||||
'opacity-30': disabled,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{avatar ? (
|
||||
<img
|
||||
src={avatar}
|
||||
style={avatarStyle}
|
||||
className={classNames(
|
||||
{
|
||||
default: 'w-[36px] h-[36px] rounded-[5px]',
|
||||
large: 'w-[48px] h-[48px] rounded-[6px]',
|
||||
}[size],
|
||||
'overflow-hidden',
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
className={classNames(
|
||||
{
|
||||
default: 'ml-[8px]',
|
||||
large: 'ml-[12px]',
|
||||
}[size],
|
||||
'flex flex-col flex-1 min-w-[0px] w-0',
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row items-center overflow-hidden">
|
||||
<p
|
||||
className={classNames(
|
||||
{
|
||||
default: 'text-[14px] leading-[20px]',
|
||||
large: 'text-[20px] leading-[28px]',
|
||||
}[size],
|
||||
'coz-fg-primary truncate flex-1 font-medium',
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</p>
|
||||
{!isShowAction || disabled ? (
|
||||
<div className="justify-self-end grid grid-flow-col gap-x-[2px]">
|
||||
{icons}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<p
|
||||
className={classNames(
|
||||
{
|
||||
default: 'text-[12px] leading-[16px] truncate',
|
||||
large:
|
||||
'text-[14px] leading-[20px] mt-[2px] text-clip line-clamp-2',
|
||||
}[size],
|
||||
'coz-fg-secondary',
|
||||
)}
|
||||
>
|
||||
{tags ? (
|
||||
<>
|
||||
{tags}
|
||||
<Divider layout="vertical" margin="4px" className="h-[9px]" />
|
||||
</>
|
||||
) : null}
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
{
|
||||
default: 'grid grid-flow-col gap-x-[2px]',
|
||||
large: 'flex gap-[4px] ml-[12px]',
|
||||
}[size],
|
||||
size === 'large' && s['actions-large'],
|
||||
{
|
||||
hidden: !isShowAction,
|
||||
'opacity-30': disabled,
|
||||
},
|
||||
)}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
{actions}
|
||||
</div>
|
||||
</div>
|
||||
</ToolTooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export const ToolItem: FC<ToolItemProps> = props => (
|
||||
<ToolItemContextProvider>
|
||||
<_ToolItem {...props} />
|
||||
</ToolItemContextProvider>
|
||||
);
|
||||
@@ -0,0 +1,31 @@
|
||||
.tool-menu-dropdown-menu {
|
||||
width: 210px;
|
||||
max-height: 590px;
|
||||
}
|
||||
|
||||
@media screen and (max-height: 750px) {
|
||||
.tool-menu-dropdown-menu {
|
||||
max-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown-item-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.dropdown-item-text {
|
||||
margin-left: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
}
|
||||
@@ -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 { type FC } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import {
|
||||
TOOL_GROUP_CONFIG,
|
||||
TOOL_KEY_TO_API_STATUS_KEY_MAP,
|
||||
type ToolKey,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Menu, Checkbox } from '@coze-arch/coze-design';
|
||||
import { TabStatus } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { ToolTooltip } from '../tool-tooltip';
|
||||
import { useRegisteredToolKeyConfigList } from '../../hooks/builtin/use-register-tool-key';
|
||||
import { useRegisteredToolGroupList } from '../../hooks/builtin/use-register-tool-group';
|
||||
import { usePreference } from '../../context/preference-context';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
type IProps = Record<string, unknown>;
|
||||
|
||||
export const ToolMenuDropdownMenu: FC<IProps> = () => {
|
||||
const registeredToolKeyConfigList = useRegisteredToolKeyConfigList();
|
||||
const registeredToolGroupList = useRegisteredToolGroupList();
|
||||
const { botSkillBlockCollapsible, setBotSkillBlockCollapsibleState } =
|
||||
usePageRuntimeStore(
|
||||
useShallow(state => ({
|
||||
botSkillBlockCollapsible: state.botSkillBlockCollapsibleState,
|
||||
setBotSkillBlockCollapsibleState:
|
||||
state.setBotSkillBlockCollapsibleState,
|
||||
})),
|
||||
);
|
||||
|
||||
const { isReadonly } = usePreference();
|
||||
|
||||
if (!registeredToolKeyConfigList.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const toolGroupKeyList = Object.keys(TOOL_GROUP_CONFIG);
|
||||
|
||||
const menuConfig = toolGroupKeyList
|
||||
.map(toolGroupKey => ({
|
||||
toolGroupKey,
|
||||
toolGroupTitle: registeredToolGroupList.find(
|
||||
toolGroupConfig => toolGroupConfig.toolGroupKey === toolGroupKey,
|
||||
)?.groupTitle,
|
||||
toolList: registeredToolKeyConfigList
|
||||
.filter(toolConfig => toolConfig.toolGroupKey === toolGroupKey)
|
||||
.map(toolConfig => toolConfig),
|
||||
}))
|
||||
.filter(toolGroup => toolGroup.toolList.length);
|
||||
|
||||
const getToolStatus = (toolKey: ToolKey) =>
|
||||
botSkillBlockCollapsible[TOOL_KEY_TO_API_STATUS_KEY_MAP[toolKey]];
|
||||
|
||||
const handleClick = (toolKey: ToolKey, currentStatus?: TabStatus) => {
|
||||
if (isReadonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
setBotSkillBlockCollapsibleState({
|
||||
[TOOL_KEY_TO_API_STATUS_KEY_MAP[toolKey]]:
|
||||
currentStatus === TabStatus.Hide ? TabStatus.Default : TabStatus.Hide,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['tool-menu-dropdown-menu']}>
|
||||
<Menu.SubMenu mode="menu">
|
||||
{menuConfig.map((toolGroup, groupIdx) => (
|
||||
<div key={toolGroup.toolGroupKey}>
|
||||
<Menu.Title style={{ paddingLeft: '32px' }}>
|
||||
{toolGroup.toolGroupTitle}
|
||||
</Menu.Title>
|
||||
{toolGroup.toolList.map(tool => {
|
||||
const toolStatus = getToolStatus(tool.toolKey);
|
||||
return (
|
||||
<ToolTooltip
|
||||
content={
|
||||
tool.hasValidData
|
||||
? I18n.t('modules_menu_guide_warning')
|
||||
: undefined
|
||||
}
|
||||
position="right"
|
||||
key={`tooltips-${tool.toolKey}`}
|
||||
>
|
||||
<Menu.Item
|
||||
style={{ display: 'block' }}
|
||||
key={tool.toolKey}
|
||||
disabled={tool.hasValidData}
|
||||
onClick={() => handleClick(tool.toolKey, toolStatus)}
|
||||
>
|
||||
<div className={styles['dropdown-item-container']}>
|
||||
<Checkbox
|
||||
checked={toolStatus !== TabStatus.Hide}
|
||||
disabled={tool.hasValidData}
|
||||
/>
|
||||
<span className={styles['dropdown-item-text']}>
|
||||
{tool.toolTitle}
|
||||
</span>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
</ToolTooltip>
|
||||
);
|
||||
})}
|
||||
{groupIdx < menuConfig.length - 1 ? <Menu.Divider /> : null}
|
||||
</div>
|
||||
))}
|
||||
</Menu.SubMenu>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState, type FC } from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Button } from '@coze-arch/coze-design';
|
||||
import { useCommonConfigStore } from '@coze-foundation/global-store';
|
||||
|
||||
import guideFallbackImage from './images/guide-fallback.png';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface IProps {
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const GuidePopover: FC<IProps> = ({ onClose }) => {
|
||||
const [fallbackUrl, setFallbackUrl] = useState('');
|
||||
|
||||
const botIdeGuideVideoUrl = useCommonConfigStore(
|
||||
state => state.commonConfigs.botIdeGuideVideoUrl,
|
||||
);
|
||||
return (
|
||||
<div className={styles.guide}>
|
||||
<p className={classnames(styles['guide-text'], 'coz-fg-primary')}>
|
||||
{I18n.t('modules_menu_guide')}
|
||||
</p>
|
||||
{fallbackUrl ? (
|
||||
<img src={fallbackUrl} className={styles['guide-image']} />
|
||||
) : (
|
||||
<video
|
||||
width={380}
|
||||
height={238}
|
||||
src={botIdeGuideVideoUrl}
|
||||
poster={guideFallbackImage}
|
||||
data-object-fit
|
||||
muted
|
||||
data-autoplay
|
||||
loop={true}
|
||||
autoPlay={true}
|
||||
onError={() => setFallbackUrl(guideFallbackImage)}
|
||||
className={styles['guide-video']}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
className={styles['guide-button']}
|
||||
type="primary"
|
||||
theme="solid"
|
||||
onClick={onClose}
|
||||
>
|
||||
{I18n.t('modules_menu_guide_gotit')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,29 @@
|
||||
.guide-popover {}
|
||||
|
||||
.guide {
|
||||
width: 380px;
|
||||
}
|
||||
|
||||
.guide-text {
|
||||
margin-bottom: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.guide-image {
|
||||
width: 380px;
|
||||
margin: 0 0 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.guide-video {
|
||||
overflow: hidden;
|
||||
width: 380px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.guide-button {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Menu, Popover, IconButton } from '@coze-arch/coze-design';
|
||||
import { IconMenu } from '@coze-arch/bot-icons';
|
||||
|
||||
import { ToolMenuDropdownMenu } from '../tool-menu-dropdown-menu';
|
||||
import { GuidePopover } from './guide-popover';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
interface IProps {
|
||||
visible?: boolean;
|
||||
newbieGuideVisible?: boolean;
|
||||
onNewbieGuidePopoverClose?: () => void;
|
||||
rePosKey: number;
|
||||
}
|
||||
|
||||
export const ToolMenu: FC<IProps> = ({
|
||||
visible = true,
|
||||
onNewbieGuidePopoverClose,
|
||||
newbieGuideVisible,
|
||||
rePosKey,
|
||||
}) => {
|
||||
const onButtonClick = () => {
|
||||
if (!newbieGuideVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
onNewbieGuidePopoverClose?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
hidden: !visible,
|
||||
[s['guide-popover'] || '']: true,
|
||||
})}
|
||||
>
|
||||
<Popover
|
||||
content={<GuidePopover onClose={onNewbieGuidePopoverClose} />}
|
||||
trigger="custom"
|
||||
visible={newbieGuideVisible && visible}
|
||||
showArrow
|
||||
onClickOutSide={onButtonClick}
|
||||
>
|
||||
<Menu
|
||||
trigger="click"
|
||||
position="bottomRight"
|
||||
render={<ToolMenuDropdownMenu />}
|
||||
rePosKey={rePosKey}
|
||||
>
|
||||
<IconButton
|
||||
size="default"
|
||||
color="secondary"
|
||||
icon={<IconMenu className="text-[16px]" />}
|
||||
onClick={onButtonClick}
|
||||
/>
|
||||
</Menu>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
.tool-popover {
|
||||
color: rgba(255, 255, 255, 79%)!important;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import { Popover, type PopoverProps } from '@coze-arch/coze-design';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
type ToolPopoverProps = {
|
||||
children: JSX.Element;
|
||||
hideToolTip?: boolean;
|
||||
} & PopoverProps;
|
||||
|
||||
export const ToolPopover: FC<ToolPopoverProps> = props => {
|
||||
const { content, children, hideToolTip, ...restProps } = props;
|
||||
return (
|
||||
<Popover
|
||||
showArrow
|
||||
position="top"
|
||||
className={s['tool-popover']}
|
||||
trigger={hideToolTip ? 'custom' : 'hover'}
|
||||
visible={hideToolTip ? false : undefined}
|
||||
content={content}
|
||||
style={{ backgroundColor: '#363D4D', padding: 8 }}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
.tool-tooltips {
|
||||
color: rgba(255, 255, 255, 79%)!important;
|
||||
background-color: #363D4D !important;
|
||||
|
||||
:global {
|
||||
.semi-tooltip-icon-arrow {
|
||||
color: #363D4D !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 FC } from 'react';
|
||||
|
||||
import { Tooltip, type TooltipProps } from '@coze-arch/coze-design';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
type ToolTooltipsProps = {
|
||||
children: JSX.Element;
|
||||
hideToolTip?: boolean;
|
||||
} & TooltipProps;
|
||||
|
||||
export const ToolTooltip: FC<ToolTooltipsProps> = props => {
|
||||
const { content, children, hideToolTip, ...restProps } = props;
|
||||
return content ? (
|
||||
<Tooltip
|
||||
trigger={hideToolTip ? 'custom' : 'hover'}
|
||||
visible={hideToolTip ? false : undefined}
|
||||
content={content}
|
||||
className={s['tool-tooltips']}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
) : (
|
||||
<>{children}</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 { Children, useMemo, type FC, type PropsWithChildren } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { AbilityScope } from '@coze-agent-ide/tool-config';
|
||||
import { Spin } from '@coze-arch/coze-design';
|
||||
import { PlacementEnum, useLayoutContext } from '@coze-arch/bot-hooks';
|
||||
|
||||
import { ToolContainer } from '../tool-container';
|
||||
import { useSubscribeToolStore } from '../../hooks/public/store/use-tool-store';
|
||||
import { useRegisterToolKey } from '../../hooks/builtin/use-register-tool-key';
|
||||
import { useRegisterToolGroup } from '../../hooks/builtin/use-register-tool-group';
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
type IProps = Record<string, unknown>;
|
||||
|
||||
export const ToolView: FC<PropsWithChildren<IProps>> = ({ children }) => {
|
||||
const {
|
||||
store: { useToolAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
const registerToolKey = useRegisterToolKey();
|
||||
const registerToolGroup = useRegisterToolGroup();
|
||||
useSubscribeToolStore(AbilityScope.TOOL);
|
||||
|
||||
const { isInitialed, isModeSwitching } = useToolAreaStore(state => ({
|
||||
isInitialed: state.isInitialed,
|
||||
isModeSwitching: state.isModeSwitching,
|
||||
}));
|
||||
|
||||
const { placement } = useLayoutContext();
|
||||
|
||||
const newChildren = useMemo(() => {
|
||||
const allChildren = Array.isArray(children) ? children : [children];
|
||||
|
||||
if (!isInitialed) {
|
||||
return isModeSwitching ? null : (
|
||||
<div
|
||||
className={classNames('w-full flex items-center justify-center', {
|
||||
'h-auto': placement === PlacementEnum.LEFT,
|
||||
'h-full': placement === PlacementEnum.CENTER,
|
||||
})}
|
||||
>
|
||||
<Spin spinning />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 遍历 GroupingContainer 的所有子元素
|
||||
return Children.map(allChildren, childLevel1 => {
|
||||
if (Children.count(childLevel1?.props?.children)) {
|
||||
return {
|
||||
...childLevel1,
|
||||
props: {
|
||||
...childLevel1.props,
|
||||
// 子元素都套一层 ToolContainer
|
||||
children: Children.map(childLevel1.props.children, childLevel2 => {
|
||||
const { toolKey, title: toolTitle } = childLevel2?.props ?? {};
|
||||
const { toolGroupKey, title: groupTitle } =
|
||||
childLevel1?.props ?? {};
|
||||
|
||||
if (!toolKey || !toolTitle || !toolGroupKey || !groupTitle) {
|
||||
return childLevel2;
|
||||
}
|
||||
|
||||
registerToolGroup({
|
||||
toolGroupKey,
|
||||
groupTitle,
|
||||
});
|
||||
|
||||
registerToolKey({
|
||||
toolKey,
|
||||
toolGroupKey,
|
||||
toolTitle,
|
||||
hasValidData: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<ToolContainer scope={AbilityScope.TOOL} toolKey={toolKey}>
|
||||
{childLevel2}
|
||||
</ToolContainer>
|
||||
);
|
||||
}),
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return childLevel1;
|
||||
}
|
||||
});
|
||||
}, [children, isInitialed]);
|
||||
|
||||
return newChildren;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 { SkillKeyEnum } from '@coze-agent-ide/tool-config';
|
||||
import { OpenBlockEvent } from '@coze-arch/bot-utils';
|
||||
type IOpenBlockEventToToolKey = Record<string, SkillKeyEnum>;
|
||||
|
||||
// `模块折叠 有关事件` 和 `模块主键` 之间的映射关系
|
||||
export const openBlockEventToToolKey: IOpenBlockEventToToolKey = {
|
||||
[OpenBlockEvent.PLUGIN_API_BLOCK_OPEN]: SkillKeyEnum.PLUGIN_API_BLOCK,
|
||||
[OpenBlockEvent.WORKFLOW_BLOCK_OPEN]: SkillKeyEnum.WORKFLOW_BLOCK,
|
||||
[OpenBlockEvent.IMAGEFLOW_BLOCK_OPEN]: SkillKeyEnum.IMAGE_BLOCK,
|
||||
[OpenBlockEvent.DATA_SET_BLOCK_OPEN]: SkillKeyEnum.DATA_SET_BLOCK,
|
||||
[OpenBlockEvent.DATA_MEMORY_BLOCK_OPEN]: SkillKeyEnum.DATA_MEMORY_BLOCK,
|
||||
[OpenBlockEvent.TABLE_MEMORY_BLOCK_OPEN]: SkillKeyEnum.TABLE_MEMORY_BLOCK,
|
||||
[OpenBlockEvent.TIME_CAPSULE_BLOCK_OPEN]: SkillKeyEnum.TIME_CAPSULE_BLOCK,
|
||||
[OpenBlockEvent.ONBORDING_MESSAGE_BLOCK_OPEN]:
|
||||
SkillKeyEnum.ONBORDING_MESSAGE_BLOCK,
|
||||
[OpenBlockEvent.TASK_MANAGE_OPEN]: SkillKeyEnum.TASK_MANAGE_BLOCK,
|
||||
[OpenBlockEvent.SUGGESTION_BLOCK_OPEN]: SkillKeyEnum.AUTO_SUGGESTION,
|
||||
[OpenBlockEvent.TTS_BLOCK_OPEN]: SkillKeyEnum.TEXT_TO_SPEECH,
|
||||
[OpenBlockEvent.FILEBOX_OPEN]: SkillKeyEnum.FILEBOX_BLOCK,
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 FC,
|
||||
type PropsWithChildren,
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
|
||||
import EventEmitter from 'eventemitter3';
|
||||
import { type BotMode } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { isValidContext } from '../utils/is-valid-context';
|
||||
import { type IAbilityStoreState } from '../typings/store';
|
||||
import { type IEventCenterEventName } from '../typings/scoped-events';
|
||||
import { type Nullable } from '../typings/index';
|
||||
import { type IEventCallbacks } from '../typings/event-callbacks';
|
||||
import { type ToolAreaStore } from '../store/tool-area';
|
||||
import { type AgentAreaStore } from '../store/agent-area';
|
||||
import { AbilityStoreProvider } from '../hooks/store/use-ability-store-context';
|
||||
import { useCreateStore } from '../hooks/builtin/use-create-store';
|
||||
|
||||
type IAbilityAreaContext = Nullable<{
|
||||
store: {
|
||||
useToolAreaStore: ToolAreaStore;
|
||||
useAgentAreaStore: AgentAreaStore;
|
||||
};
|
||||
scopedEventBus: EventEmitter<IEventCenterEventName>;
|
||||
eventCallbacks: Partial<IEventCallbacks>;
|
||||
}>;
|
||||
|
||||
const DEFAULT_ABILITY_AREA: IAbilityAreaContext = {
|
||||
store: null,
|
||||
scopedEventBus: null,
|
||||
eventCallbacks: null,
|
||||
};
|
||||
|
||||
const AbilityAreaContext =
|
||||
createContext<IAbilityAreaContext>(DEFAULT_ABILITY_AREA);
|
||||
|
||||
export const AbilityAreaContextProvider: FC<
|
||||
PropsWithChildren<{
|
||||
eventCallbacks?: Partial<IEventCallbacks>;
|
||||
mode: BotMode;
|
||||
modeSwitching: boolean;
|
||||
isInit: boolean;
|
||||
}>
|
||||
> = ({ children, eventCallbacks = {}, mode, modeSwitching, isInit }) => {
|
||||
const store = useCreateStore();
|
||||
const scopedEventBus = useMemo(() => new EventEmitter<string>(), []);
|
||||
|
||||
const { useToolAreaStore, useAgentAreaStore } = store;
|
||||
|
||||
const clearAgentAreaStore = useAgentAreaStore(state => state.clearStore);
|
||||
const {
|
||||
updateIsInitialed,
|
||||
updateIsModeSwitching,
|
||||
clearStore: clearToolAreaStore,
|
||||
} = useToolAreaStore.getState();
|
||||
/**
|
||||
* 清除
|
||||
*/
|
||||
useEffect(() => {
|
||||
updateIsModeSwitching(modeSwitching);
|
||||
|
||||
if (modeSwitching || !isInit) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateIsInitialed(true);
|
||||
eventCallbacks?.onInitialed?.();
|
||||
|
||||
const cleanUp = () => {
|
||||
updateIsInitialed(false);
|
||||
eventCallbacks?.onDestroy?.();
|
||||
clearToolAreaStore();
|
||||
clearAgentAreaStore();
|
||||
};
|
||||
|
||||
return cleanUp;
|
||||
}, [mode, modeSwitching, isInit]);
|
||||
|
||||
return (
|
||||
<AbilityAreaContext.Provider
|
||||
value={{
|
||||
store,
|
||||
scopedEventBus,
|
||||
eventCallbacks,
|
||||
}}
|
||||
>
|
||||
<AbilityStore>{children}</AbilityStore>
|
||||
</AbilityAreaContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const AbilityStore: FC<PropsWithChildren> = ({ children }) => {
|
||||
const [state, setState] = useState<IAbilityStoreState>({});
|
||||
|
||||
return (
|
||||
<AbilityStoreProvider state={state} setState={setState}>
|
||||
{children}
|
||||
</AbilityStoreProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAbilityAreaContext = () => {
|
||||
const toolAreaContext = useContext(AbilityAreaContext);
|
||||
|
||||
if (!isValidContext(toolAreaContext)) {
|
||||
throw new Error('toolAreaContext is not valid');
|
||||
}
|
||||
|
||||
return toolAreaContext;
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 FC,
|
||||
type PropsWithChildren,
|
||||
createContext,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import {
|
||||
type AbilityKey,
|
||||
type AbilityScope,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
|
||||
interface IAbilityConfigContext {
|
||||
abilityKey?: AbilityKey;
|
||||
scope?: AbilityScope;
|
||||
}
|
||||
|
||||
const DEFAULT_ABILITY_CONFIG = {
|
||||
abilityKey: undefined,
|
||||
scope: undefined,
|
||||
};
|
||||
|
||||
const AbilityConfigContext = createContext<IAbilityConfigContext>(
|
||||
DEFAULT_ABILITY_CONFIG,
|
||||
);
|
||||
|
||||
export const AbilityConfigContextProvider: FC<
|
||||
PropsWithChildren<IAbilityConfigContext>
|
||||
> = props => {
|
||||
const { children, ...rest } = props;
|
||||
|
||||
return (
|
||||
<AbilityConfigContext.Provider value={rest}>
|
||||
{children}
|
||||
</AbilityConfigContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAbilityConfigContext = () => useContext(AbilityConfigContext);
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 FC,
|
||||
type PropsWithChildren,
|
||||
createContext,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import { type AgentSkillKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
interface IAgentSkillConfigContext {
|
||||
agentSkillKey?: AgentSkillKey;
|
||||
}
|
||||
|
||||
const DEFAULT_AGENT_SKILL_CONFIG = {
|
||||
agentSkillKey: undefined,
|
||||
};
|
||||
|
||||
const AgentSkillConfigContext = createContext<IAgentSkillConfigContext>(
|
||||
DEFAULT_AGENT_SKILL_CONFIG,
|
||||
);
|
||||
|
||||
export const AgentSkillConfigContextProvider: FC<
|
||||
PropsWithChildren<IAgentSkillConfigContext>
|
||||
> = props => {
|
||||
const { children, ...rest } = props;
|
||||
|
||||
return (
|
||||
<AgentSkillConfigContext.Provider value={rest}>
|
||||
{children}
|
||||
</AgentSkillConfigContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAgentSkillConfigContext = () =>
|
||||
useContext(AgentSkillConfigContext);
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type FC,
|
||||
type PropsWithChildren,
|
||||
createContext,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
export interface IPreferenceContext {
|
||||
/**
|
||||
* 是否开启Tool隐藏模式
|
||||
*/
|
||||
enableToolHiddenMode: boolean;
|
||||
/**
|
||||
* 是否只读状态
|
||||
*/
|
||||
isReadonly: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_PREFERENCE: IPreferenceContext = {
|
||||
enableToolHiddenMode: false,
|
||||
isReadonly: false,
|
||||
};
|
||||
|
||||
const PreferenceContext = createContext<IPreferenceContext>(DEFAULT_PREFERENCE);
|
||||
|
||||
export const PreferenceContextProvider: FC<
|
||||
PropsWithChildren<Partial<IPreferenceContext>>
|
||||
> = props => {
|
||||
const { children, ...rest } = props;
|
||||
|
||||
return (
|
||||
<PreferenceContext.Provider value={merge({}, DEFAULT_PREFERENCE, rest)}>
|
||||
{children}
|
||||
</PreferenceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePreference = () => useContext(PreferenceContext);
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 FC,
|
||||
type PropsWithChildren,
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
export interface IToolItemContext {
|
||||
isForceShowAction: boolean;
|
||||
setIsForceShowAction: (visible: boolean) => void;
|
||||
}
|
||||
|
||||
const DEFAULT_TOOL_ITEM_CONTEXT: IToolItemContext = {
|
||||
isForceShowAction: false,
|
||||
setIsForceShowAction: (visible: boolean) => false,
|
||||
};
|
||||
|
||||
const ToolItemContext = createContext<IToolItemContext>(
|
||||
DEFAULT_TOOL_ITEM_CONTEXT,
|
||||
);
|
||||
|
||||
export const ToolItemContextProvider: FC<PropsWithChildren> = props => {
|
||||
const { children } = props;
|
||||
|
||||
const [_isForceShowAction, _setIsForceShowAction] = useState(false);
|
||||
|
||||
return (
|
||||
<ToolItemContext.Provider
|
||||
value={merge({}, DEFAULT_TOOL_ITEM_CONTEXT, {
|
||||
isForceShowAction: _isForceShowAction,
|
||||
setIsForceShowAction: _setIsForceShowAction,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</ToolItemContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useToolItemContext = () => useContext(ToolItemContext);
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 AgentModalTabKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useEvent } from '../event/use-event';
|
||||
import { EventCenterEventName } from '../../typings/scoped-events';
|
||||
import {
|
||||
type IAgentModalTabChangeEventParams,
|
||||
type IAgentModalVisibleChangeEventParams,
|
||||
} from '../../typings/event';
|
||||
|
||||
/**
|
||||
* 内部使用的方法,不对外使用,用于抛出事件
|
||||
*/
|
||||
export const useAgentModalTriggerEvent = () => {
|
||||
const { emit } = useEvent();
|
||||
|
||||
const emitTabChangeEvent = (tabKey: AgentModalTabKey) => {
|
||||
emit<IAgentModalTabChangeEventParams>(
|
||||
EventCenterEventName.AgentModalTabChange,
|
||||
{ tabKey },
|
||||
);
|
||||
};
|
||||
|
||||
const emitModalVisibleChangeEvent = (isVisible: boolean) => {
|
||||
emit<IAgentModalVisibleChangeEventParams>(
|
||||
EventCenterEventName.AgentModalVisibleChange,
|
||||
{
|
||||
isVisible,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return { emitTabChangeEvent, emitModalVisibleChangeEvent };
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import {
|
||||
AgentSkillModal,
|
||||
type IAgentSkillModalPane,
|
||||
} from '../../components/agent-skill-modal';
|
||||
import { useAgentModalTriggerEvent } from './use-agent-modal-trigger-event';
|
||||
|
||||
export const useAgentSkillModal = (tabPanes: IAgentSkillModalPane[]) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const { emitModalVisibleChangeEvent } = useAgentModalTriggerEvent();
|
||||
const close = () => {
|
||||
setVisible(false);
|
||||
emitModalVisibleChangeEvent(false);
|
||||
};
|
||||
const open = () => {
|
||||
setVisible(true);
|
||||
emitModalVisibleChangeEvent(true);
|
||||
};
|
||||
return {
|
||||
node: visible ? (
|
||||
<AgentSkillModal tabPanes={tabPanes} onCancel={close} />
|
||||
) : null,
|
||||
close,
|
||||
open,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 { useShallow } from 'zustand/react/shallow';
|
||||
import { type AgentSkillKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
/**
|
||||
* @deprecated 内部使用,过渡期方案,针对非注册组件使用外部的skill设置
|
||||
*/
|
||||
export const useHasAgentSkillWithPK = () => {
|
||||
const {
|
||||
store: { useAgentAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const { existManualAgentSkillKey, realSetHasAgentSkill } = useAgentAreaStore(
|
||||
state => ({
|
||||
existManualAgentSkillKey: state.existManualAgentSkillKey,
|
||||
realSetHasAgentSkill: state.setHasAgentSkillKey,
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated 内部使用,过渡期
|
||||
*/
|
||||
const setHasAgentSkill = (
|
||||
agentSkillKey: AgentSkillKey,
|
||||
hasSkill: boolean,
|
||||
) => {
|
||||
const isManual = existManualAgentSkillKey(agentSkillKey);
|
||||
|
||||
if (!isManual) {
|
||||
realSetHasAgentSkill(agentSkillKey, hasSkill);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
setHasAgentSkill,
|
||||
};
|
||||
};
|
||||
|
||||
export const useNoneAgentSkill = () => {
|
||||
const {
|
||||
store: { useAgentAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const noneAgentSkill = useAgentAreaStore(
|
||||
useShallow(state =>
|
||||
state.registeredAgentSkillKeyList.every(
|
||||
agentSkillKey => !state.hasAgentSkillKeyList.includes(agentSkillKey),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return noneAgentSkill;
|
||||
};
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
import { useAbilityConfigContext } from '../../context/ability-config-context';
|
||||
|
||||
/**
|
||||
* 用户内部获取ToolKey使用
|
||||
*/
|
||||
export const useAbilityConfig = () => {
|
||||
const { abilityKey, scope } = useAbilityConfigContext();
|
||||
|
||||
return { abilityKey, scope };
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 { useMemo } from 'react';
|
||||
|
||||
import { createToolAreaStore } from '../../store/tool-area';
|
||||
import { createAgentAreaStore } from '../../store/agent-area';
|
||||
|
||||
export const useCreateStore = () => {
|
||||
const memoedUseToolAreaStore = useMemo(() => createToolAreaStore(), []);
|
||||
const memoedUseAgentAreaStore = useMemo(() => createAgentAreaStore(), []);
|
||||
|
||||
return {
|
||||
useToolAreaStore: memoedUseToolAreaStore,
|
||||
useAgentAreaStore: memoedUseAgentAreaStore,
|
||||
};
|
||||
};
|
||||
@@ -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 AbilityKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
export const useGetToolConfig = () => {
|
||||
const {
|
||||
store: { useToolAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const registeredToolKeyConfigList = useToolAreaStore(
|
||||
state => state.registeredToolKeyConfigList,
|
||||
);
|
||||
|
||||
return (abilityKey?: AbilityKey) =>
|
||||
registeredToolKeyConfigList.find(
|
||||
toolConfig => toolConfig.toolKey === abilityKey,
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 AgentSkillKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
/**
|
||||
* 用于内部注册AgentSkill使用
|
||||
*/
|
||||
export const useRegisterAgentSkillKey = () => {
|
||||
const {
|
||||
store: { useAgentAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const appendRegisteredAgentSkillKeyList = useAgentAreaStore(
|
||||
state => state.appendRegisteredAgentSkillKeyList,
|
||||
);
|
||||
|
||||
return (agentSkillKey: AgentSkillKey) => {
|
||||
appendRegisteredAgentSkillKeyList(agentSkillKey);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import { type IRegisteredToolGroupConfig } from '../../store/tool-area';
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
export const useRegisterToolGroup = () => {
|
||||
const {
|
||||
store: { useToolAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
const appendIntoRegisteredToolGroupList = useToolAreaStore(
|
||||
useShallow(state => state.appendIntoRegisteredToolGroupList),
|
||||
);
|
||||
|
||||
return (params: IRegisteredToolGroupConfig) => {
|
||||
appendIntoRegisteredToolGroupList(params);
|
||||
};
|
||||
};
|
||||
|
||||
export const useRegisteredToolGroupList = () => {
|
||||
const {
|
||||
store: { useToolAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const registeredToolGroupList = useToolAreaStore(
|
||||
useShallow(state => state.registeredToolGroupList),
|
||||
);
|
||||
|
||||
return registeredToolGroupList;
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import { type IRegisteredToolKeyConfig } from '../../store/tool-area';
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
/**
|
||||
* 用于内部注册Tool使用
|
||||
*/
|
||||
export const useRegisterToolKey = () => {
|
||||
const {
|
||||
store: { useToolAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
const appendIntoRegisteredToolKeyConfigList = useToolAreaStore(
|
||||
useShallow(state => state.appendIntoRegisteredToolKeyConfigList),
|
||||
);
|
||||
|
||||
return (params: IRegisteredToolKeyConfig) => {
|
||||
appendIntoRegisteredToolKeyConfigList(params);
|
||||
};
|
||||
};
|
||||
|
||||
export const useRegisteredToolKeyConfigList = () => {
|
||||
const {
|
||||
store: { useToolAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const registeredToolKeyConfigList = useToolAreaStore(
|
||||
useShallow(state => state.registeredToolKeyConfigList),
|
||||
);
|
||||
|
||||
return registeredToolKeyConfigList;
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { useAbilityAreaContext } from '../../context/ability-area-context';
|
||||
|
||||
export const useEvent = () => {
|
||||
const { scopedEventBus } = useAbilityAreaContext();
|
||||
|
||||
function on<T extends Record<string, any>>(
|
||||
eventName: string,
|
||||
listener: (params: T) => void,
|
||||
) {
|
||||
scopedEventBus.on(eventName, listener);
|
||||
|
||||
return () => {
|
||||
scopedEventBus.off(eventName, listener);
|
||||
};
|
||||
}
|
||||
|
||||
function once<T extends Record<string, any>>(
|
||||
eventName: string,
|
||||
listener: (params: T) => void,
|
||||
) {
|
||||
scopedEventBus.once(eventName, listener);
|
||||
}
|
||||
|
||||
function emit<T extends Record<string, any>>(eventName: string, params: T) {
|
||||
scopedEventBus.emit(eventName, params);
|
||||
}
|
||||
|
||||
return {
|
||||
on,
|
||||
once,
|
||||
emit,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 { useShallow } from 'zustand/react/shallow';
|
||||
import { type AgentSkillKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useAbilityAreaContext } from '../../../context/ability-area-context';
|
||||
|
||||
export const useHasAgentSkill = () => {
|
||||
const {
|
||||
store: { useAgentAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
const {
|
||||
setHasAgentSkillKey,
|
||||
existHasAgentSkillKey,
|
||||
appendManualAgentSkillKeyList,
|
||||
} = useAgentAreaStore(
|
||||
useShallow(state => ({
|
||||
setHasAgentSkillKey: state.setHasAgentSkillKey,
|
||||
existHasAgentSkillKey: state.existHasAgentSkillKey,
|
||||
appendManualAgentSkillKeyList: state.appendManualAgentSkillKeyList,
|
||||
})),
|
||||
);
|
||||
|
||||
const setHasAgentSkill = (
|
||||
agentSkillKey: AgentSkillKey,
|
||||
hasSkill: boolean,
|
||||
) => {
|
||||
setHasAgentSkillKey(agentSkillKey, hasSkill);
|
||||
appendManualAgentSkillKeyList(agentSkillKey);
|
||||
};
|
||||
|
||||
const getHasAgentSkill = (agentSkillKey: AgentSkillKey) =>
|
||||
existHasAgentSkillKey(agentSkillKey);
|
||||
|
||||
return {
|
||||
setHasAgentSkill,
|
||||
getHasAgentSkill,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 { useMemo } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { size } from 'lodash-es';
|
||||
import { type SkillKeyEnum } from '@coze-agent-ide/tool-config';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import {
|
||||
TabStatus,
|
||||
type TabDisplayItems,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { useAbilityConfig } from '../../builtin/use-ability-config';
|
||||
import { toolKeyToApiStatusKeyTransformer } from '../../../utils/tool-content-block';
|
||||
|
||||
/**
|
||||
* 用于校验当前模块默认展开收起状态
|
||||
*
|
||||
* @param blockKey 主键 - tool 插件化改造后无需传入
|
||||
* @param configured 是否有配置内容
|
||||
* @param when 是否校验
|
||||
*
|
||||
* @see
|
||||
*/
|
||||
export const useToolContentBlockDefaultExpand = (
|
||||
$params: {
|
||||
blockKey?: SkillKeyEnum;
|
||||
configured: boolean;
|
||||
},
|
||||
$when = true,
|
||||
) => {
|
||||
const { abilityKey } = useAbilityConfig();
|
||||
const { blockKey, configured = false } = $params;
|
||||
const isReadonly = useBotDetailIsReadonly();
|
||||
const { init, editable, botSkillBlockCollapsibleState } = usePageRuntimeStore(
|
||||
useShallow(store => ({
|
||||
init: store.init,
|
||||
editable: store.editable,
|
||||
botSkillBlockCollapsibleState: store.botSkillBlockCollapsibleState,
|
||||
})),
|
||||
);
|
||||
return useMemo(() => {
|
||||
// 不做校验
|
||||
if (!$when) {
|
||||
return undefined;
|
||||
// 状态机未就绪
|
||||
} else if (!init || size(botSkillBlockCollapsibleState) === 0) {
|
||||
return undefined;
|
||||
/**
|
||||
* @description 仅在满足以下条件时用户行为记录才能生效
|
||||
*
|
||||
* 1. 拥有编辑权限
|
||||
* 2. 不能是历史预览环境
|
||||
* 3. 必须已配置
|
||||
*/
|
||||
} else if (editable && !isReadonly && configured) {
|
||||
const key = abilityKey ?? blockKey;
|
||||
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
const transformerBlockKey = toolKeyToApiStatusKeyTransformer(key);
|
||||
const collapsibleState =
|
||||
botSkillBlockCollapsibleState[
|
||||
transformerBlockKey as keyof TabDisplayItems
|
||||
];
|
||||
|
||||
if (collapsibleState === TabStatus.Open) {
|
||||
return true;
|
||||
} else if (collapsibleState === TabStatus.Close) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return configured;
|
||||
}, [
|
||||
$when,
|
||||
blockKey,
|
||||
configured,
|
||||
init,
|
||||
isReadonly,
|
||||
editable,
|
||||
botSkillBlockCollapsibleState,
|
||||
]);
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 AbilityKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useEvent } from '../../event/use-event';
|
||||
import { EventCenterEventName } from '../../../typings/scoped-events';
|
||||
import { type IToggleContentBlockEventParams } from '../../../typings/event';
|
||||
|
||||
interface IUseToolToggleCollapseParams {
|
||||
abilityKeyList: AbilityKey[];
|
||||
isExpand: boolean;
|
||||
}
|
||||
|
||||
export const useToolToggleCollapse = () => {
|
||||
const { emit } = useEvent();
|
||||
|
||||
return ({ abilityKeyList, isExpand }: IUseToolToggleCollapseParams) => {
|
||||
if (!abilityKeyList.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
abilityKeyList.forEach(abilityKey => {
|
||||
emit<IToggleContentBlockEventParams>(
|
||||
EventCenterEventName.ToggleContentBlock,
|
||||
{
|
||||
abilityKey,
|
||||
isExpand,
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 { useShallow } from 'zustand/react/shallow';
|
||||
import { TOOL_KEY_TO_API_STATUS_KEY_MAP } from '@coze-agent-ide/tool-config';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { TabStatus } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { useRegisteredToolKeyConfigList } from '../../builtin/use-register-tool-key';
|
||||
import { usePreference } from '../../../context/preference-context';
|
||||
|
||||
export const useIsAllToolHidden = () => {
|
||||
const { isReadonly } = usePreference();
|
||||
const botSkillBlockCollapsibleState = usePageRuntimeStore(
|
||||
useShallow(state => state.botSkillBlockCollapsibleState),
|
||||
);
|
||||
|
||||
const registeredToolKeyConfigList = useRegisteredToolKeyConfigList();
|
||||
|
||||
if (isReadonly) {
|
||||
return registeredToolKeyConfigList.every(
|
||||
toolConfig => !toolConfig.hasValidData,
|
||||
);
|
||||
}
|
||||
|
||||
const statusKeyMap = registeredToolKeyConfigList.map(
|
||||
toolConfig => TOOL_KEY_TO_API_STATUS_KEY_MAP[toolConfig.toolKey],
|
||||
);
|
||||
|
||||
return statusKeyMap.every(
|
||||
statusKey => botSkillBlockCollapsibleState[statusKey] === TabStatus.Hide,
|
||||
);
|
||||
};
|
||||
@@ -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 { TOOL_KEY_TO_API_STATUS_KEY_MAP } from '@coze-agent-ide/tool-config';
|
||||
import { usePageRuntimeStore } from '@coze-studio/bot-detail-store/page-runtime';
|
||||
import { TabStatus } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { useAbilityConfig } from '../../builtin/use-ability-config';
|
||||
import { isToolKey } from '../../../utils/is-tool-key';
|
||||
import { usePreference } from '../../../context/preference-context';
|
||||
import { useAbilityAreaContext } from '../../../context/ability-area-context';
|
||||
|
||||
export const useToolValidData = () => {
|
||||
const {
|
||||
store: { useToolAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const setToolHasValidData = useToolAreaStore(
|
||||
state => state.setToolHasValidData,
|
||||
);
|
||||
|
||||
const setBotSkillBlockCollapsibleState = usePageRuntimeStore(
|
||||
state => state.setBotSkillBlockCollapsibleState,
|
||||
);
|
||||
|
||||
const { abilityKey, scope } = useAbilityConfig();
|
||||
|
||||
const toolStatus = usePageRuntimeStore(state =>
|
||||
abilityKey
|
||||
? state.botSkillBlockCollapsibleState[
|
||||
TOOL_KEY_TO_API_STATUS_KEY_MAP[abilityKey]
|
||||
]
|
||||
: null,
|
||||
);
|
||||
|
||||
const { isReadonly } = usePreference();
|
||||
|
||||
return (hasValidData: boolean) => {
|
||||
if (!isToolKey(abilityKey, scope)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setToolHasValidData({
|
||||
toolKey: abilityKey,
|
||||
hasValidData,
|
||||
});
|
||||
|
||||
/**
|
||||
* 异常场景兜底,视图和服务端数据无法匹配,需要触发更新服务端数据
|
||||
* 有数据但是隐藏状态
|
||||
*/
|
||||
if (toolStatus === TabStatus.Hide && hasValidData) {
|
||||
setBotSkillBlockCollapsibleState(
|
||||
{
|
||||
[TOOL_KEY_TO_API_STATUS_KEY_MAP[abilityKey]]: TabStatus.Default,
|
||||
},
|
||||
isReadonly,
|
||||
);
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 { useShallow } from 'zustand/react/shallow';
|
||||
import {
|
||||
AbilityScope,
|
||||
type ToolKey,
|
||||
type AgentSkillKey,
|
||||
type AbilityKey,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useEvent } from '../../event/use-event';
|
||||
import { useAbilityConfig } from '../../builtin/use-ability-config';
|
||||
import { generateError } from '../../../utils/error';
|
||||
import { EventCenterEventName } from '../../../typings/scoped-events';
|
||||
import { type IAbilityInitialedEventParams } from '../../../typings/event';
|
||||
import { useAbilityAreaContext } from '../../../context/ability-area-context';
|
||||
|
||||
export const useInit = () => {
|
||||
const { on, emit } = useEvent();
|
||||
const { abilityKey, scope } = useAbilityConfig();
|
||||
|
||||
if (!abilityKey || !scope) {
|
||||
throw generateError('AbilityKey or Scope is undefined');
|
||||
}
|
||||
|
||||
const {
|
||||
store: { useToolAreaStore, useAgentAreaStore },
|
||||
} = useAbilityAreaContext();
|
||||
|
||||
const { registeredToolKeyConfigList, appendIntoInitialedToolKeyList } =
|
||||
useToolAreaStore(
|
||||
useShallow(state => ({
|
||||
registeredToolKeyConfigList: state.registeredToolKeyConfigList,
|
||||
appendIntoInitialedToolKeyList: state.appendIntoInitialedToolKeyList,
|
||||
})),
|
||||
);
|
||||
|
||||
const { registeredAgentSkillKeyList, appendIntoInitialedAgentSkillKeyList } =
|
||||
useAgentAreaStore(
|
||||
useShallow(state => ({
|
||||
registeredAgentSkillKeyList: state.registeredAgentSkillKeyList,
|
||||
appendIntoInitialedAgentSkillKeyList:
|
||||
state.appendIntoInitialedAgentSkillKeyList,
|
||||
})),
|
||||
);
|
||||
|
||||
function markToolInitialed() {
|
||||
let updatedInitialedAbilityKeyList: ToolKey[] | AgentSkillKey[] = [];
|
||||
|
||||
if (scope === AbilityScope.TOOL) {
|
||||
appendIntoInitialedToolKeyList(abilityKey as unknown as ToolKey);
|
||||
updatedInitialedAbilityKeyList =
|
||||
useToolAreaStore.getState().initialedToolKeyList;
|
||||
} else if (scope === AbilityScope.AGENT_SKILL) {
|
||||
appendIntoInitialedAgentSkillKeyList(
|
||||
abilityKey as unknown as AgentSkillKey,
|
||||
);
|
||||
updatedInitialedAbilityKeyList =
|
||||
useAgentAreaStore.getState().initialedAgentSkillKeyList;
|
||||
}
|
||||
|
||||
emit<IAbilityInitialedEventParams>(EventCenterEventName.AbilityInitialed, {
|
||||
initialedAbilityKeyList: updatedInitialedAbilityKeyList,
|
||||
});
|
||||
}
|
||||
|
||||
function onToolInitialed(
|
||||
listener: () => void,
|
||||
listenedAbilityKey: AbilityKey,
|
||||
) {
|
||||
const offToolInitialed = on<IAbilityInitialedEventParams>(
|
||||
EventCenterEventName.AbilityInitialed,
|
||||
params => {
|
||||
const { initialedAbilityKeyList } = params;
|
||||
if (initialedAbilityKeyList.includes(listenedAbilityKey)) {
|
||||
listener();
|
||||
offToolInitialed();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function onAllToolInitialed(listener: (isAllInitialed: boolean) => void) {
|
||||
const offToolInitialed = on<IAbilityInitialedEventParams>(
|
||||
EventCenterEventName.AbilityInitialed,
|
||||
params => {
|
||||
const { initialedAbilityKeyList } = params;
|
||||
|
||||
let isAllRegisteredAbilityKeyInitialed = false;
|
||||
|
||||
if (scope === AbilityScope.TOOL) {
|
||||
isAllRegisteredAbilityKeyInitialed =
|
||||
registeredToolKeyConfigList.every(toolKeyConfig =>
|
||||
initialedAbilityKeyList.includes(toolKeyConfig.toolKey),
|
||||
);
|
||||
} else if (scope === AbilityScope.AGENT_SKILL) {
|
||||
isAllRegisteredAbilityKeyInitialed =
|
||||
registeredAgentSkillKeyList.every(agentSkillKey =>
|
||||
initialedAbilityKeyList.includes(agentSkillKey),
|
||||
);
|
||||
}
|
||||
|
||||
listener(isAllRegisteredAbilityKeyInitialed);
|
||||
},
|
||||
);
|
||||
|
||||
return offToolInitialed;
|
||||
}
|
||||
|
||||
return {
|
||||
markToolInitialed,
|
||||
onToolInitialed,
|
||||
onAllToolInitialed,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @coze-arch/no-pkg-dir-import
|
||||
import { type AgentModalTabKey } from '@coze-agent-ide/tool-config/src/types';
|
||||
|
||||
import { useEvent } from '../../event/use-event';
|
||||
import { EventCenterEventName } from '../../../typings/scoped-events';
|
||||
import {
|
||||
type IAgentModalTabChangeEventParams,
|
||||
type IAgentModalVisibleChangeEventParams,
|
||||
} from '../../../typings/event';
|
||||
|
||||
export const useAgentSkillModalCallbacks = () => {
|
||||
const { on } = useEvent();
|
||||
const onTabChange = (listener: (tabKey: AgentModalTabKey) => void) => {
|
||||
on<IAgentModalTabChangeEventParams>(
|
||||
EventCenterEventName.AgentModalTabChange,
|
||||
params => {
|
||||
const { tabKey } = params;
|
||||
listener(tabKey);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const onModalVisibleChange = (listener: (isVisible: boolean) => void) => {
|
||||
on<IAgentModalVisibleChangeEventParams>(
|
||||
EventCenterEventName.AgentModalVisibleChange,
|
||||
params => {
|
||||
const { isVisible } = params;
|
||||
listener(isVisible);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
onTabChange,
|
||||
onModalVisibleChange,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 { useEffect } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { size } from 'lodash-es';
|
||||
import {
|
||||
AbilityScope,
|
||||
TOOL_KEY_STORE_MAP,
|
||||
AGENT_SKILL_KEY_MAP,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
import { useMultiAgentStore } from '@coze-studio/bot-detail-store/multi-agent';
|
||||
import {
|
||||
type BotSkillAction,
|
||||
type BotSkillStore,
|
||||
useBotSkillStore,
|
||||
} from '@coze-studio/bot-detail-store/bot-skill';
|
||||
import { findTargetAgent } from '@coze-studio/bot-detail-store';
|
||||
|
||||
import { useAbilityStoreContext } from '../../store/use-ability-store-context';
|
||||
import { useAbilityConfig } from '../../builtin/use-ability-config';
|
||||
import { generateError } from '../../../utils/error';
|
||||
|
||||
const KEY_MAP = {
|
||||
[AbilityScope.TOOL]: TOOL_KEY_STORE_MAP,
|
||||
[AbilityScope.AGENT_SKILL]: AGENT_SKILL_KEY_MAP,
|
||||
};
|
||||
|
||||
// 访问全局状态机中的状态
|
||||
export function useToolStore<U>(selector: (state: BotSkillStore) => U): U {
|
||||
const { abilityKey } = useAbilityConfig();
|
||||
|
||||
if (!abilityKey) {
|
||||
throw generateError('not find abilityKey');
|
||||
}
|
||||
|
||||
return useBotSkillStore(selector) as U;
|
||||
}
|
||||
|
||||
// 访问全局状态机中的方法
|
||||
export function useToolStoreAction<U>(
|
||||
selector: (state: BotSkillAction) => U,
|
||||
): U {
|
||||
const { abilityKey } = useAbilityConfig();
|
||||
|
||||
if (!abilityKey) {
|
||||
throw generateError('not find abilityKey');
|
||||
}
|
||||
|
||||
return useBotSkillStore(selector) as U;
|
||||
}
|
||||
|
||||
// 提交数据
|
||||
export function useToolDispatch<T>() {
|
||||
const { abilityKey, scope } = useAbilityConfig();
|
||||
|
||||
const { state, setState } = useAbilityStoreContext();
|
||||
|
||||
if (!abilityKey || !scope) {
|
||||
throw generateError('not find abilityKey or scope');
|
||||
}
|
||||
|
||||
return (newState: T) => {
|
||||
setState({
|
||||
[scope]: {
|
||||
...state[scope],
|
||||
// @ts-expect-error -- 以后想着解决一下这里的类型问题
|
||||
[KEY_MAP[scope][abilityKey]]: newState,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// 监听 tool 状态机数据变化,并同步到 bot detail store
|
||||
export function useSubscribeToolStore(scope: AbilityScope, agentId?: string) {
|
||||
// bot detail store 更新方法
|
||||
const { setBotSkill } = useBotSkillStore(
|
||||
useShallow(state => ({
|
||||
setBotSkill: state.setBotSkill,
|
||||
})),
|
||||
);
|
||||
const { setMultiAgentByImmer } = useMultiAgentStore(
|
||||
useShallow(state => ({
|
||||
setMultiAgentByImmer: state.setMultiAgentByImmer,
|
||||
})),
|
||||
);
|
||||
|
||||
// tools store 数据
|
||||
const { state } = useAbilityStoreContext();
|
||||
const newState = state[scope];
|
||||
|
||||
// 同步数据
|
||||
useEffect(() => {
|
||||
if (size(newState)) {
|
||||
if (!newState) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (scope === AbilityScope.TOOL) {
|
||||
setBotSkill(newState);
|
||||
} else if (scope === AbilityScope.AGENT_SKILL) {
|
||||
setMultiAgentByImmer(agentState => {
|
||||
const agent = findTargetAgent(agentState.agents, agentId);
|
||||
if (agent) {
|
||||
agent.skills = newState;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [newState]);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 FC,
|
||||
type PropsWithChildren,
|
||||
createContext,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import { noop } from 'lodash-es';
|
||||
|
||||
import { type IAbilityStoreState } from '../../typings/store';
|
||||
|
||||
interface IAbilityStoreContext {
|
||||
state: IAbilityStoreState;
|
||||
setState: (state: IAbilityStoreState) => void;
|
||||
}
|
||||
|
||||
const AbilityStoreContext = createContext<IAbilityStoreContext>({
|
||||
state: {},
|
||||
setState: noop,
|
||||
});
|
||||
|
||||
export const AbilityStoreProvider: FC<
|
||||
PropsWithChildren<IAbilityStoreContext>
|
||||
> = ({ children, state, setState }) => (
|
||||
<AbilityStoreContext.Provider
|
||||
value={{
|
||||
state,
|
||||
setState,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AbilityStoreContext.Provider>
|
||||
);
|
||||
|
||||
export const useAbilityStoreContext = () => useContext(AbilityStoreContext);
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 AbilityKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
import { useEvent } from '../event/use-event';
|
||||
import { EventCenterEventName } from '../../typings/scoped-events';
|
||||
import { type IToggleContentBlockEventParams } from '../../typings/event';
|
||||
|
||||
/**
|
||||
* 私有的hooks,不对外暴露使用
|
||||
* @returns
|
||||
*/
|
||||
|
||||
export const useRegisterCollapse = () => {
|
||||
const { on } = useEvent();
|
||||
|
||||
const registerCollapse = (
|
||||
listener: (isExpand: boolean) => void,
|
||||
abilityKey: AbilityKey,
|
||||
) =>
|
||||
on<IToggleContentBlockEventParams>(
|
||||
EventCenterEventName.ToggleContentBlock,
|
||||
params => {
|
||||
const { abilityKey: currentAbilityKey, isExpand } = params;
|
||||
|
||||
if (abilityKey === currentAbilityKey) {
|
||||
listener(isExpand);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
registerCollapse,
|
||||
};
|
||||
};
|
||||
97
frontend/packages/agent-ide/tool/src/index.ts
Normal file
97
frontend/packages/agent-ide/tool/src/index.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* START 对外长期暴露的类型、常量、函数、Hooks、组件等
|
||||
*/
|
||||
export {
|
||||
AbilityScope,
|
||||
ToolKey,
|
||||
AgentSkillKey,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
|
||||
export {
|
||||
useToolStore,
|
||||
useToolStoreAction,
|
||||
useToolDispatch,
|
||||
useSubscribeToolStore,
|
||||
} from './hooks/public/store/use-tool-store';
|
||||
|
||||
export { openBlockEventToToolKey } from './constants/tool-content-block';
|
||||
|
||||
export { useToolContentBlockDefaultExpand } from './hooks/public/collapse/use-tool-content-block-default-expand';
|
||||
export { useAgentSkillModal } from './hooks/agent-skill-modal/use-agent-skill-modal';
|
||||
export { useToolToggleCollapse } from './hooks/public/collapse/use-tool-toggle-collapse';
|
||||
export { useInit } from './hooks/public/init/use-init';
|
||||
export { useRegisteredToolKeyConfigList } from './hooks/builtin/use-register-tool-key';
|
||||
export { useIsAllToolHidden } from './hooks/public/container/use-tool-all-hidden';
|
||||
export { useToolValidData } from './hooks/public/container/use-tool-valid-data';
|
||||
|
||||
export { ToolContentBlock } from './components/tool-content-block';
|
||||
export { AbilityAreaContextProvider } from './context/ability-area-context';
|
||||
export { ToolView } from './components/tool-view';
|
||||
export { ToolContainer } from './components/tool-container';
|
||||
export { ToolMenu } from './components/tool-menu';
|
||||
export { GroupingContainer } from './components/grouping-container';
|
||||
export { AbilityAreaContainer } from './components/ability-area-container';
|
||||
|
||||
export { ToolEntryCommonProps } from './typings/index';
|
||||
|
||||
export { ToolItemList } from './components/tool-item-list';
|
||||
export { ToolItem } from './components/tool-item';
|
||||
export { ToolItemSwitch } from './components/tool-item-switch';
|
||||
export { ToolItemAction } from './components/tool-item-action';
|
||||
export { ToolItemActionCard } from './components/tool-item-action/actions/tool-item-action-card';
|
||||
export { ToolItemActionCopy } from './components/tool-item-action/actions/tool-item-action-copy';
|
||||
export { ToolItemActionDelete } from './components/tool-item-action/actions/tool-item-action-delete';
|
||||
export { ToolItemActionInfo } from './components/tool-item-action/actions/tool-item-action-info';
|
||||
export { ToolItemActionSetting } from './components/tool-item-action/actions/tool-item-action-setting';
|
||||
export { ToolItemActionEdit } from './components/tool-item-action/actions/tool-item-action-edit';
|
||||
export { ToolItemActionDrag } from './components/tool-item-action/actions/tool-item-action-drag';
|
||||
export { ToolItemIconInfo } from './components/tool-item-icon/icons/tool-item-icon-info';
|
||||
export { ToolItemIconPeople } from './components/tool-item-icon/icons/tool-item-icon-people';
|
||||
export { ToolItemIconCard } from './components/tool-item-icon/icons/tool-item-icon-card';
|
||||
export { useToolItemContext } from './context/tool-item-context';
|
||||
export { AutoGenerateButton } from './components/auto-generate-button';
|
||||
export { AddButton } from './components/add-button';
|
||||
export { TipsDisplay as ModelCapabilityTipsDisplay } from './components/model-capability-tips';
|
||||
|
||||
export { abilityKey2ModelFunctionConfigType } from './utils/model-function-config-type-mapping';
|
||||
|
||||
/**
|
||||
* END 对外长期暴露的类型、常量、函数、Hooks、组件等
|
||||
*/
|
||||
|
||||
/**
|
||||
* START 过渡期对外暴露的类型、常量、函数、Hooks、组件等
|
||||
*/
|
||||
export {
|
||||
/**
|
||||
* 模块主键
|
||||
* @deprecated 该使用方式已废弃, 请使用: `import { ToolKey } from '@coze-agent-ide/tool-config'`;
|
||||
*/
|
||||
SkillKeyEnum,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
|
||||
export { useHasAgentSkillWithPK } from './hooks/agent-skill/use-agent-skill';
|
||||
|
||||
export { useEvent } from './hooks/event/use-event';
|
||||
|
||||
export { EventCenterEventName } from './typings/scoped-events';
|
||||
export { IToggleContentBlockEventParams } from './typings/event';
|
||||
/**
|
||||
* END 过渡期对外暴露的类型、常量、函数、Hooks、组件等
|
||||
*/
|
||||
131
frontend/packages/agent-ide/tool/src/store/agent-area.ts
Normal file
131
frontend/packages/agent-ide/tool/src/store/agent-area.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 { produce } from 'immer';
|
||||
import { type AgentSkillKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
export interface IAgentAreaState {
|
||||
/**
|
||||
* @deprecated 过渡期使用,用户手动搞的key list
|
||||
*/
|
||||
manualAgentSkillKeyList: AgentSkillKey[];
|
||||
hasAgentSkillKeyList: AgentSkillKey[];
|
||||
initialedAgentSkillKeyList: AgentSkillKey[];
|
||||
registeredAgentSkillKeyList: AgentSkillKey[];
|
||||
}
|
||||
|
||||
export interface IAgentAreaAction {
|
||||
/**
|
||||
* @deprecated 过渡期使用,后续删除
|
||||
*/
|
||||
appendManualAgentSkillKeyList: (skillKey: AgentSkillKey) => void;
|
||||
setHasAgentSkillKey: (skillKey: AgentSkillKey, hasSkill: boolean) => void;
|
||||
existHasAgentSkillKey: (skillKey: AgentSkillKey) => boolean;
|
||||
appendRegisteredAgentSkillKeyList: (skillKey: AgentSkillKey) => void;
|
||||
hasAgentSkillKeyInRegisteredAgentSkillKeyList: (
|
||||
skillKey: AgentSkillKey,
|
||||
) => boolean;
|
||||
existManualAgentSkillKey: (skillKey: AgentSkillKey) => boolean;
|
||||
appendIntoInitialedAgentSkillKeyList: (skillKey: AgentSkillKey) => void;
|
||||
clearStore: () => void;
|
||||
}
|
||||
|
||||
export const createAgentAreaStore = () =>
|
||||
create<IAgentAreaState & IAgentAreaAction>()(
|
||||
devtools(
|
||||
(set, get) => ({
|
||||
manualAgentSkillKeyList: [],
|
||||
hasAgentSkillKeyList: [],
|
||||
registeredAgentSkillKeyList: [],
|
||||
initialedAgentSkillKeyList: [],
|
||||
setHasAgentSkillKey: (skillKey, hasSkill) => {
|
||||
set(
|
||||
produce<IAgentAreaState>(state => {
|
||||
const { hasAgentSkillKeyList } = state;
|
||||
|
||||
if (hasSkill) {
|
||||
if (!hasAgentSkillKeyList.includes(skillKey)) {
|
||||
hasAgentSkillKeyList.push(skillKey);
|
||||
}
|
||||
} else {
|
||||
const index = hasAgentSkillKeyList.findIndex(
|
||||
key => key === skillKey,
|
||||
);
|
||||
if (index >= 0) {
|
||||
hasAgentSkillKeyList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
existHasAgentSkillKey: skillKey => {
|
||||
const { hasAgentSkillKeyList } = get();
|
||||
return hasAgentSkillKeyList.includes(skillKey);
|
||||
},
|
||||
appendRegisteredAgentSkillKeyList: (skillKey: AgentSkillKey) => {
|
||||
const { registeredAgentSkillKeyList } = get();
|
||||
if (!registeredAgentSkillKeyList.includes(skillKey)) {
|
||||
set({
|
||||
registeredAgentSkillKeyList: [
|
||||
...registeredAgentSkillKeyList,
|
||||
skillKey,
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
hasAgentSkillKeyInRegisteredAgentSkillKeyList: (
|
||||
skillKey: AgentSkillKey,
|
||||
) => {
|
||||
const { registeredAgentSkillKeyList } = get();
|
||||
return registeredAgentSkillKeyList.includes(skillKey);
|
||||
},
|
||||
appendManualAgentSkillKeyList: skillKey => {
|
||||
const { manualAgentSkillKeyList } = get();
|
||||
if (!manualAgentSkillKeyList.includes(skillKey)) {
|
||||
set({
|
||||
manualAgentSkillKeyList: [...manualAgentSkillKeyList, skillKey],
|
||||
});
|
||||
}
|
||||
},
|
||||
existManualAgentSkillKey: skillKey =>
|
||||
get().manualAgentSkillKeyList.includes(skillKey),
|
||||
appendIntoInitialedAgentSkillKeyList: skillKey => {
|
||||
const { initialedAgentSkillKeyList } = get();
|
||||
if (!initialedAgentSkillKeyList.includes(skillKey)) {
|
||||
set({
|
||||
initialedAgentSkillKeyList: [
|
||||
...initialedAgentSkillKeyList,
|
||||
skillKey,
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
clearStore: () => {
|
||||
set({
|
||||
hasAgentSkillKeyList: [],
|
||||
});
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'botStudio.tool.AgentAreaStore',
|
||||
enabled: IS_DEV_MODE,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export type AgentAreaStore = ReturnType<typeof createAgentAreaStore>;
|
||||
151
frontend/packages/agent-ide/tool/src/store/tool-area.ts
Normal file
151
frontend/packages/agent-ide/tool/src/store/tool-area.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 { produce } from 'immer';
|
||||
import { type ToolKey, type ToolGroupKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
export interface IRegisteredToolKeyConfig {
|
||||
toolGroupKey: ToolGroupKey;
|
||||
toolKey: ToolKey;
|
||||
toolTitle: string;
|
||||
hasValidData: boolean;
|
||||
}
|
||||
|
||||
export interface IRegisteredToolGroupConfig {
|
||||
toolGroupKey: ToolGroupKey;
|
||||
groupTitle: string;
|
||||
}
|
||||
|
||||
export interface IToolAreaState {
|
||||
isInitialed: boolean;
|
||||
isModeSwitching: boolean;
|
||||
initialedToolKeyList: ToolKey[];
|
||||
registeredToolKeyConfigList: IRegisteredToolKeyConfig[];
|
||||
registeredToolGroupList: IRegisteredToolGroupConfig[];
|
||||
}
|
||||
|
||||
export interface IToolAreaAction {
|
||||
updateIsInitialed: (isInitialed: boolean) => void;
|
||||
updateIsModeSwitching: (isModeSwitching: boolean) => void;
|
||||
appendIntoInitialedToolKeyList: (toolKey: ToolKey) => void;
|
||||
hasToolKeyInInitialedToolKeyList: (toolKey: ToolKey) => boolean;
|
||||
setToolHasValidData: (data: {
|
||||
toolKey: ToolKey;
|
||||
hasValidData: boolean;
|
||||
}) => void;
|
||||
appendIntoRegisteredToolKeyConfigList: (
|
||||
params: IRegisteredToolKeyConfig,
|
||||
) => void;
|
||||
appendIntoRegisteredToolGroupList: (
|
||||
params: IRegisteredToolGroupConfig,
|
||||
) => void;
|
||||
hasToolKeyInRegisteredToolKeyList: (toolKey: ToolKey) => boolean;
|
||||
clearStore: () => void;
|
||||
}
|
||||
|
||||
export const createToolAreaStore = () =>
|
||||
create<IToolAreaState & IToolAreaAction>()(
|
||||
devtools(
|
||||
(set, get) => ({
|
||||
initialedToolKeyList: [],
|
||||
registeredToolKeyConfigList: [],
|
||||
registeredToolGroupList: [],
|
||||
isInitialed: false,
|
||||
isModeSwitching: false,
|
||||
appendIntoRegisteredToolKeyConfigList: params => {
|
||||
const { toolKey } = params;
|
||||
const { registeredToolKeyConfigList } = get();
|
||||
if (
|
||||
!registeredToolKeyConfigList.find(
|
||||
toolKeyConfig => toolKeyConfig.toolKey === toolKey,
|
||||
)
|
||||
) {
|
||||
set({
|
||||
registeredToolKeyConfigList: [
|
||||
...registeredToolKeyConfigList,
|
||||
params,
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
hasToolKeyInRegisteredToolKeyList: (toolKey: ToolKey) => {
|
||||
const { registeredToolKeyConfigList } = get();
|
||||
return Boolean(
|
||||
registeredToolKeyConfigList.find(
|
||||
toolKeyConfig => toolKeyConfig.toolKey === toolKey,
|
||||
),
|
||||
);
|
||||
},
|
||||
setToolHasValidData: ({ toolKey, hasValidData }) => {
|
||||
set(
|
||||
produce<IToolAreaState>(state => {
|
||||
const tool = state.registeredToolKeyConfigList.find(
|
||||
toolConfig => toolConfig.toolKey === toolKey,
|
||||
);
|
||||
|
||||
if (tool) {
|
||||
tool.hasValidData = hasValidData;
|
||||
}
|
||||
}),
|
||||
);
|
||||
},
|
||||
appendIntoRegisteredToolGroupList: params => {
|
||||
const { registeredToolGroupList } = get();
|
||||
|
||||
if (
|
||||
!registeredToolGroupList.find(
|
||||
groupConfig => groupConfig.toolGroupKey === params.toolGroupKey,
|
||||
)
|
||||
) {
|
||||
set({
|
||||
registeredToolGroupList: [...registeredToolGroupList, params],
|
||||
});
|
||||
}
|
||||
},
|
||||
appendIntoInitialedToolKeyList: (toolKey: ToolKey) => {
|
||||
const { initialedToolKeyList } = get();
|
||||
if (!initialedToolKeyList.includes(toolKey)) {
|
||||
set({
|
||||
initialedToolKeyList: [...initialedToolKeyList, toolKey],
|
||||
});
|
||||
}
|
||||
},
|
||||
hasToolKeyInInitialedToolKeyList: (toolKey: ToolKey) => {
|
||||
const { initialedToolKeyList } = get();
|
||||
return initialedToolKeyList.includes(toolKey);
|
||||
},
|
||||
updateIsInitialed: (isInitialed: boolean) => set({ isInitialed }),
|
||||
updateIsModeSwitching: (isModeSwitching: boolean) =>
|
||||
set({ isModeSwitching }),
|
||||
clearStore: () => {
|
||||
set({
|
||||
initialedToolKeyList: [],
|
||||
registeredToolKeyConfigList: [],
|
||||
registeredToolGroupList: [],
|
||||
isInitialed: false,
|
||||
});
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'botStudio.tool.ToolAreaStore',
|
||||
enabled: IS_DEV_MODE,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export type ToolAreaStore = ReturnType<typeof createToolAreaStore>;
|
||||
22
frontend/packages/agent-ide/tool/src/typings.d.ts
vendored
Normal file
22
frontend/packages/agent-ide/tool/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
|
||||
declare module '*.less' {
|
||||
const resource: { [key: string]: string };
|
||||
export = resource;
|
||||
}
|
||||
25
frontend/packages/agent-ide/tool/src/typings/button.ts
Normal file
25
frontend/packages/agent-ide/tool/src/typings/button.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
export interface ToolButtonCommonProps {
|
||||
onClick?: () => void;
|
||||
tooltips?: ReactNode;
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
[key: `data-${string}`]: string;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 interface IEventCallbacks {
|
||||
onAllToolHiddenStatusChange: (isAllHidden: boolean) => void;
|
||||
onInitialed: () => void;
|
||||
onDestroy: () => void;
|
||||
}
|
||||
37
frontend/packages/agent-ide/tool/src/typings/event.ts
Normal file
37
frontend/packages/agent-ide/tool/src/typings/event.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 AgentModalTabKey,
|
||||
type AbilityKey,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
|
||||
export interface IAbilityInitialedEventParams {
|
||||
initialedAbilityKeyList: Array<AbilityKey>;
|
||||
}
|
||||
|
||||
export interface IToggleContentBlockEventParams {
|
||||
abilityKey: AbilityKey;
|
||||
isExpand: boolean;
|
||||
}
|
||||
|
||||
export interface IAgentModalTabChangeEventParams {
|
||||
tabKey: AgentModalTabKey;
|
||||
}
|
||||
|
||||
export interface IAgentModalVisibleChangeEventParams {
|
||||
isVisible: boolean;
|
||||
}
|
||||
32
frontend/packages/agent-ide/tool/src/typings/index.ts
Normal file
32
frontend/packages/agent-ide/tool/src/typings/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 ToolKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
export type Nullable<T> = {
|
||||
[P in keyof T]: T[P] | null;
|
||||
};
|
||||
|
||||
export type NonNullableType<T> = {
|
||||
[P in keyof T]: Exclude<T[P], null>;
|
||||
};
|
||||
|
||||
export type EmptyFunc = () => void | Promise<void>;
|
||||
|
||||
export interface ToolEntryCommonProps {
|
||||
title: string;
|
||||
toolKey?: ToolKey;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 type IEventCenterEventName = EventCenterEventName | string;
|
||||
|
||||
/**
|
||||
* 事件中心内置的事件
|
||||
*/
|
||||
export const enum EventCenterEventName {
|
||||
/**
|
||||
* 插件初始化后的事件名
|
||||
*/
|
||||
AbilityInitialed = 'abilityInitialed',
|
||||
/**
|
||||
* 折叠展开ContentBlock的事件
|
||||
*/
|
||||
ToggleContentBlock = 'toggleContentBlock',
|
||||
/**
|
||||
* Agent Modal中tab切换的事件
|
||||
*/
|
||||
AgentModalTabChange = 'agentModalTabChange',
|
||||
/**
|
||||
* Agent Modal中显隐发生变化
|
||||
*/
|
||||
AgentModalVisibleChange = 'agentModalVisibleChange',
|
||||
}
|
||||
25
frontend/packages/agent-ide/tool/src/typings/store.ts
Normal file
25
frontend/packages/agent-ide/tool/src/typings/store.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 AbilityScope } from '@coze-agent-ide/tool-config';
|
||||
import { type BotDetailSkill } from '@coze-studio/bot-detail-store';
|
||||
|
||||
type BotSkillType = BotDetailSkill;
|
||||
|
||||
export interface IAbilityStoreState {
|
||||
[AbilityScope.TOOL]?: BotSkillType;
|
||||
[AbilityScope.AGENT_SKILL]?: BotDetailSkill;
|
||||
}
|
||||
18
frontend/packages/agent-ide/tool/src/utils/error.ts
Normal file
18
frontend/packages/agent-ide/tool/src/utils/error.ts
Normal file
@@ -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 const generateError = (message: string) =>
|
||||
new Error(`[Bot Platform Tool Hooks]: ${message}`);
|
||||
29
frontend/packages/agent-ide/tool/src/utils/has-valid-key.ts
Normal file
29
frontend/packages/agent-ide/tool/src/utils/has-valid-key.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { type ReactElement, type ReactNode } from 'react';
|
||||
|
||||
import { type AgentSkillKey } from '@coze-agent-ide/tool-config';
|
||||
|
||||
export function hasValidAgentSkillKey(
|
||||
child: ReactNode,
|
||||
): child is ReactElement<unknown> & { key: AgentSkillKey } {
|
||||
return (
|
||||
React.isValidElement(child) &&
|
||||
child.key !== null &&
|
||||
typeof child.key === 'string'
|
||||
);
|
||||
}
|
||||
24
frontend/packages/agent-ide/tool/src/utils/is-tool-key.ts
Normal file
24
frontend/packages/agent-ide/tool/src/utils/is-tool-key.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 AbilityKey,
|
||||
type AbilityScope,
|
||||
type ToolKey,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
|
||||
export const isToolKey = (_?: AbilityKey, scope?: AbilityScope): _ is ToolKey =>
|
||||
scope === 'tool';
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 NonNullableType } from '../typings/index';
|
||||
|
||||
export const isValidContext = <T extends object>(
|
||||
context: T,
|
||||
): context is NonNullableType<T> =>
|
||||
Object.keys(context)
|
||||
.map(keyName => context[keyName as keyof T])
|
||||
.reduce(
|
||||
(prevResult, currentProperty) => prevResult && currentProperty !== null,
|
||||
true,
|
||||
);
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 AbilityKey } from '@coze-agent-ide/tool-config';
|
||||
import { ModelFuncConfigType } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
// AbilityKey 到 ModelFuncConfigType 的映射
|
||||
const abilityKeyFuncConfigTypeMap: {
|
||||
// 确保每个 key 这里都有配置
|
||||
[key in AbilityKey]: ModelFuncConfigType | null;
|
||||
} = {
|
||||
plugin: ModelFuncConfigType.Plugin,
|
||||
workflow: ModelFuncConfigType.Workflow,
|
||||
knowledge: null,
|
||||
imageflow: ModelFuncConfigType.ImageFlow,
|
||||
variable: ModelFuncConfigType.Variable,
|
||||
database: ModelFuncConfigType.Database,
|
||||
longTermMemory: ModelFuncConfigType.LongTermMemory,
|
||||
fileBox: ModelFuncConfigType.FileBox,
|
||||
trigger: ModelFuncConfigType.Trigger,
|
||||
onboarding: ModelFuncConfigType.Onboarding,
|
||||
suggest: ModelFuncConfigType.Suggestion,
|
||||
voice: ModelFuncConfigType.TTS,
|
||||
background: ModelFuncConfigType.BackGroundImage,
|
||||
document: ModelFuncConfigType.KnowledgeText,
|
||||
table: ModelFuncConfigType.KnowledgeTable,
|
||||
photo: ModelFuncConfigType.KnowledgePhoto,
|
||||
shortcut: ModelFuncConfigType.ShortcutCommand,
|
||||
devHooks: ModelFuncConfigType.HookInfo,
|
||||
userInput: ModelFuncConfigType.TTS,
|
||||
};
|
||||
|
||||
export const abilityKey2ModelFunctionConfigType = (abilityKey: AbilityKey) =>
|
||||
abilityKeyFuncConfigTypeMap[abilityKey];
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 ToolKey,
|
||||
TOOL_KEY_TO_API_STATUS_KEY_MAP,
|
||||
type AbilityKey,
|
||||
type SkillKeyEnum,
|
||||
} from '@coze-agent-ide/tool-config';
|
||||
|
||||
/**
|
||||
* `能力模块主键` 转 `接口定义的属性名` 函数
|
||||
* ⚠️ 命名需参看 @/services/auto-generate/developer_api/namespaces/developer_api > TabDisplayItems
|
||||
*/
|
||||
export const toolKeyToApiStatusKeyTransformer = (
|
||||
$key: AbilityKey | SkillKeyEnum,
|
||||
) => {
|
||||
const apiStatusKey = TOOL_KEY_TO_API_STATUS_KEY_MAP[$key as ToolKey];
|
||||
return apiStatusKey ?? `${$key}_tab_status`;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user