@lobehub/lobehub 2.0.0-next.94 → 2.0.0-next.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/issue-auto-comments.yml +0 -19
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/common.json +21 -0
- package/locales/ar/hotkey.json +4 -0
- package/locales/bg-BG/common.json +21 -0
- package/locales/bg-BG/hotkey.json +4 -0
- package/locales/de-DE/common.json +21 -0
- package/locales/de-DE/hotkey.json +4 -0
- package/locales/en-US/common.json +21 -0
- package/locales/en-US/hotkey.json +4 -0
- package/locales/es-ES/common.json +21 -0
- package/locales/es-ES/hotkey.json +4 -0
- package/locales/fa-IR/common.json +21 -0
- package/locales/fa-IR/hotkey.json +4 -0
- package/locales/fr-FR/common.json +21 -0
- package/locales/fr-FR/hotkey.json +4 -0
- package/locales/it-IT/common.json +21 -0
- package/locales/it-IT/hotkey.json +4 -0
- package/locales/ja-JP/common.json +21 -0
- package/locales/ja-JP/hotkey.json +4 -0
- package/locales/ko-KR/common.json +21 -0
- package/locales/ko-KR/hotkey.json +4 -0
- package/locales/nl-NL/common.json +21 -0
- package/locales/nl-NL/hotkey.json +4 -0
- package/locales/pl-PL/common.json +21 -0
- package/locales/pl-PL/hotkey.json +4 -0
- package/locales/pt-BR/common.json +21 -0
- package/locales/pt-BR/hotkey.json +4 -0
- package/locales/ru-RU/common.json +21 -0
- package/locales/ru-RU/hotkey.json +4 -0
- package/locales/tr-TR/common.json +21 -0
- package/locales/tr-TR/hotkey.json +4 -0
- package/locales/vi-VN/common.json +21 -0
- package/locales/vi-VN/hotkey.json +4 -0
- package/locales/zh-CN/common.json +21 -0
- package/locales/zh-CN/hotkey.json +4 -0
- package/locales/zh-TW/common.json +21 -0
- package/locales/zh-TW/hotkey.json +4 -0
- package/package.json +3 -1
- package/packages/agent-runtime/src/core/InterventionChecker.ts +85 -0
- package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +492 -22
- package/packages/agent-runtime/src/core/defaultSecurityBlacklist.ts +335 -0
- package/packages/agent-runtime/src/core/index.ts +1 -0
- package/packages/agent-runtime/src/types/state.ts +10 -1
- package/packages/const/src/hotkeys.ts +6 -0
- package/packages/conversation-flow/src/__tests__/indexing.test.ts +513 -0
- package/packages/conversation-flow/src/__tests__/structuring.test.ts +600 -0
- package/packages/types/src/hotkey.ts +1 -0
- package/packages/types/src/tool/intervention.ts +38 -0
- package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +41 -8
- package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +6 -4
- package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/index.tsx +16 -4
- package/src/app/[variants]/(main)/settings/provider/(list)/index.tsx +15 -3
- package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +23 -15
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +25 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +28 -0
- package/src/layout/GlobalProvider/Cmdk.tsx +470 -0
- package/src/layout/GlobalProvider/CmdkLazy.tsx +17 -0
- package/src/layout/GlobalProvider/index.tsx +2 -0
- package/src/locales/default/common.ts +21 -0
- package/src/locales/default/hotkey.ts +4 -0
- package/src/store/chat/agents/GeneralChatAgent.ts +22 -8
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useResponsive, useTheme } from 'antd-style';
|
|
4
|
-
import { memo, useRef } from 'react';
|
|
4
|
+
import { memo, useEffect, useRef } from 'react';
|
|
5
5
|
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
import { useSearchParams } from 'react-router-dom';
|
|
6
7
|
|
|
7
8
|
import SettingContainer from '@/features/Setting/SettingContainer';
|
|
8
|
-
import { parseAsStringEnum, useQueryParam } from '@/hooks/useQueryParam';
|
|
9
9
|
import { SettingsTabs } from '@/store/global/initialState';
|
|
10
10
|
|
|
11
11
|
import CategoryContent from '../CategoryContent';
|
|
@@ -13,18 +13,51 @@ import SettingsContent from '../SettingsContent';
|
|
|
13
13
|
import { LayoutProps } from '../type';
|
|
14
14
|
import Header from './Header';
|
|
15
15
|
import SideBar from './SideBar';
|
|
16
|
+
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
|
16
17
|
|
|
17
18
|
const Layout = memo<LayoutProps>(() => {
|
|
18
19
|
const ref = useRef<HTMLDivElement | null>(null);
|
|
19
20
|
const { md = true } = useResponsive();
|
|
20
21
|
const theme = useTheme();
|
|
21
22
|
|
|
22
|
-
const [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
24
|
+
|
|
25
|
+
const [activeTabState, setActiveTabState] = useMergedState({
|
|
26
|
+
active: searchParams.get('active') as SettingsTabs ? searchParams.get('active') as SettingsTabs : SettingsTabs.Common,
|
|
27
|
+
}, {
|
|
28
|
+
onChange: (obj: {
|
|
29
|
+
active: SettingsTabs;
|
|
30
|
+
provider?: string;
|
|
31
|
+
}) => {
|
|
32
|
+
if (obj.provider) {
|
|
33
|
+
setSearchParams({ active: obj.active, provider: obj.provider });
|
|
34
|
+
} else {
|
|
35
|
+
searchParams.delete('provider');
|
|
36
|
+
setSearchParams({ active: obj.active });
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const setActiveTab = (tab: SettingsTabs) => {
|
|
42
|
+
if (tab === SettingsTabs.Provider) {
|
|
43
|
+
setActiveTabState({ active: tab, provider: 'all' });
|
|
44
|
+
} else {
|
|
45
|
+
setActiveTabState({
|
|
46
|
+
active: tab,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
return () => {
|
|
53
|
+
setSearchParams((prevParams) => {
|
|
54
|
+
prevParams.delete('active');
|
|
55
|
+
return prevParams;
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
26
59
|
|
|
27
|
-
const category = <CategoryContent activeTab={
|
|
60
|
+
const category = <CategoryContent activeTab={activeTabState.active} onMenuSelect={setActiveTab} />;
|
|
28
61
|
|
|
29
62
|
return (
|
|
30
63
|
<Flexbox
|
|
@@ -39,7 +72,7 @@ const Layout = memo<LayoutProps>(() => {
|
|
|
39
72
|
<Header getContainer={() => ref.current!}>{category}</Header>
|
|
40
73
|
)}
|
|
41
74
|
<SettingContainer maxWidth={'none'}>
|
|
42
|
-
<SettingsContent activeTab={
|
|
75
|
+
<SettingsContent activeTab={activeTabState.active} mobile={false} />
|
|
43
76
|
</SettingContainer>
|
|
44
77
|
</Flexbox>
|
|
45
78
|
);
|
|
@@ -5,7 +5,6 @@ import { memo } from 'react';
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
|
-
import Link from '@/components/Link';
|
|
9
8
|
import { AiProviderListItem } from '@/types/aiProvider';
|
|
10
9
|
|
|
11
10
|
import EnableSwitch from './EnableSwitch';
|
|
@@ -13,9 +12,10 @@ import { useStyles } from './style';
|
|
|
13
12
|
|
|
14
13
|
interface ProviderCardProps extends AiProviderListItem {
|
|
15
14
|
loading?: boolean;
|
|
15
|
+
onProviderSelect: (provider: string) => void;
|
|
16
16
|
}
|
|
17
17
|
const ProviderCard = memo<ProviderCardProps>(
|
|
18
|
-
({ id, description, name, enabled, source, logo, loading }) => {
|
|
18
|
+
({ id, description, name, enabled, source, logo, loading, onProviderSelect }) => {
|
|
19
19
|
const { t } = useTranslation('providers');
|
|
20
20
|
const { cx, styles, theme } = useStyles();
|
|
21
21
|
|
|
@@ -33,7 +33,9 @@ const ProviderCard = memo<ProviderCardProps>(
|
|
|
33
33
|
return (
|
|
34
34
|
<Flexbox className={cx(styles.container)} gap={24}>
|
|
35
35
|
<Flexbox gap={12} padding={16} width={'100%'}>
|
|
36
|
-
<
|
|
36
|
+
<div onClick={() => {
|
|
37
|
+
onProviderSelect(id);
|
|
38
|
+
}} style={{ cursor: 'pointer' }}>
|
|
37
39
|
<Flexbox gap={12} width={'100%'}>
|
|
38
40
|
<Flexbox align={'center'} horizontal justify={'space-between'}>
|
|
39
41
|
{source === 'builtin' ? (
|
|
@@ -68,7 +70,7 @@ const ProviderCard = memo<ProviderCardProps>(
|
|
|
68
70
|
{source === 'custom' ? description : t(`${id}.description`)}
|
|
69
71
|
</Text>
|
|
70
72
|
</Flexbox>
|
|
71
|
-
</
|
|
73
|
+
</div>
|
|
72
74
|
<Divider style={{ margin: '4px 0' }} />
|
|
73
75
|
<Flexbox horizontal justify={'space-between'}>
|
|
74
76
|
<div />
|
|
@@ -14,7 +14,12 @@ const loadingArr = Array.from({ length: 12 })
|
|
|
14
14
|
.fill('-')
|
|
15
15
|
.map((item, index) => `${index}x${item}`);
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
type ListProps = {
|
|
18
|
+
onProviderSelect: (provider: string) => void;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const List = memo((props: ListProps) => {
|
|
22
|
+
const { onProviderSelect } = props;
|
|
18
23
|
const { t } = useTranslation('modelProvider');
|
|
19
24
|
const enabledList = useAiInfraStore(aiProviderSelectors.enabledAiProviderList, isEqual);
|
|
20
25
|
const disabledList = useAiInfraStore(aiProviderSelectors.disabledAiProviderList, isEqual);
|
|
@@ -30,7 +35,14 @@ const List = memo(() => {
|
|
|
30
35
|
</Flexbox>
|
|
31
36
|
<Grid gap={16} rows={3}>
|
|
32
37
|
{loadingArr.map((item) => (
|
|
33
|
-
<Card
|
|
38
|
+
<Card
|
|
39
|
+
enabled={false}
|
|
40
|
+
id={item}
|
|
41
|
+
key={item}
|
|
42
|
+
loading
|
|
43
|
+
onProviderSelect={onProviderSelect}
|
|
44
|
+
source={'builtin'}
|
|
45
|
+
/>
|
|
34
46
|
))}
|
|
35
47
|
</Grid>
|
|
36
48
|
</Flexbox>
|
|
@@ -47,7 +59,7 @@ const List = memo(() => {
|
|
|
47
59
|
</Flexbox>
|
|
48
60
|
<Grid gap={16} rows={3}>
|
|
49
61
|
{enabledList.map((item) => (
|
|
50
|
-
<Card {...item} key={item.id} />
|
|
62
|
+
<Card {...item} key={item.id} onProviderSelect={onProviderSelect} />
|
|
51
63
|
))}
|
|
52
64
|
</Grid>
|
|
53
65
|
</Flexbox>
|
|
@@ -60,7 +72,7 @@ const List = memo(() => {
|
|
|
60
72
|
</Flexbox>
|
|
61
73
|
<Grid gap={16} rows={3}>
|
|
62
74
|
{disabledList.map((item) => (
|
|
63
|
-
<Card {...item} key={item.id} />
|
|
75
|
+
<Card {...item} key={item.id} onProviderSelect={onProviderSelect} />
|
|
64
76
|
))}
|
|
65
77
|
</Grid>
|
|
66
78
|
</Flexbox>
|
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { isCustomBranding } from '@/const/version';
|
|
4
|
-
import { parseAsString, useQueryParam } from '@/hooks/useQueryParam';
|
|
5
4
|
|
|
6
5
|
import DesktopLayout from '../_layout/Desktop';
|
|
7
6
|
import MobileLayout from '../_layout/Mobile';
|
|
8
7
|
import ProviderDetailPage from '../detail';
|
|
9
8
|
import Footer from './Footer';
|
|
9
|
+
import { useMemo, useState } from 'react';
|
|
10
|
+
import { useSearchParams } from 'react-router-dom';
|
|
10
11
|
|
|
11
12
|
const Page = (props: { mobile?: boolean }) => {
|
|
12
|
-
const [
|
|
13
|
+
const [SearchParams, setSearchParams] = useSearchParams();
|
|
14
|
+
const [provider, setProviderState] = useState(SearchParams.get('provider') || 'all');
|
|
15
|
+
const setProvider = (provider: string) => {
|
|
16
|
+
setSearchParams({ active: 'provider', provider });
|
|
17
|
+
setProviderState(provider);
|
|
18
|
+
};
|
|
19
|
+
|
|
13
20
|
const { mobile } = props;
|
|
14
21
|
const ProviderLayout = mobile ? MobileLayout : DesktopLayout;
|
|
22
|
+
|
|
23
|
+
const ProviderListPage = useMemo(() => {
|
|
24
|
+
return <ProviderDetailPage id={provider} onProviderSelect={setProvider} />;
|
|
25
|
+
}, [provider]);
|
|
26
|
+
|
|
15
27
|
return (
|
|
16
28
|
<ProviderLayout onProviderSelect={setProvider}>
|
|
17
|
-
|
|
29
|
+
{ProviderListPage}
|
|
18
30
|
{!isCustomBranding && <Footer />}
|
|
19
31
|
</ProviderLayout>
|
|
20
32
|
);
|
|
@@ -1,22 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import Azure from './azure';
|
|
4
|
-
import AzureAI from './azureai';
|
|
5
|
-
import Bedrock from './bedrock';
|
|
6
|
-
import Cloudflare from './cloudflare';
|
|
7
|
-
import ComfyUI from './comfyui';
|
|
8
|
-
import DefaultPage from './default/ProviderDetialPage';
|
|
9
|
-
import GitHub from './github';
|
|
10
|
-
import Ollama from './ollama';
|
|
11
|
-
import OpenAI from './openai';
|
|
12
|
-
import VertexAI from './vertexai';
|
|
1
|
+
import dynamic from 'next/dynamic';
|
|
2
|
+
import Loading from '@/components/Loading/BrandTextLoading';
|
|
13
3
|
|
|
14
|
-
const
|
|
15
|
-
|
|
4
|
+
const NewAPI = dynamic(() => import('./newapi'), { loading: () => <Loading />, ssr: false });
|
|
5
|
+
const OpenAI = dynamic(() => import('./openai'), { loading: () => <Loading />, ssr: false });
|
|
6
|
+
const VertexAI = dynamic(() => import('./vertexai'), { loading: () => <Loading />, ssr: false });
|
|
7
|
+
const GitHub = dynamic(() => import('./github'), { loading: () => <Loading />, ssr: false });
|
|
8
|
+
const Ollama = dynamic(() => import('./ollama'), { loading: () => <Loading />, ssr: false });
|
|
9
|
+
const ComfyUI = dynamic(() => import('./comfyui'), { loading: () => <Loading />, ssr: false });
|
|
10
|
+
const Cloudflare = dynamic(() => import('./cloudflare'), { loading: () => <Loading />, ssr: false });
|
|
11
|
+
const Bedrock = dynamic(() => import('./bedrock'), { loading: () => <Loading />, ssr: false });
|
|
12
|
+
const AzureAI = dynamic(() => import('./azureai'), { loading: () => <Loading />, ssr: false });
|
|
13
|
+
const Azure = dynamic(() => import('./azure'), { loading: () => <Loading />, ssr: false });
|
|
14
|
+
const ProviderGrid = dynamic(() => import('../(list)/ProviderGrid'), { loading: () => <Loading />, ssr: false });
|
|
15
|
+
const DefaultPage = dynamic(() => import('./default/ProviderDetialPage'), { loading: () => <Loading />, ssr: false });
|
|
16
|
+
|
|
17
|
+
type ProviderDetailPageProps = {
|
|
18
|
+
id?: string | null;
|
|
19
|
+
onProviderSelect: (provider: string) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const ProviderDetailPage = (props: ProviderDetailPageProps) => {
|
|
23
|
+
const { id, onProviderSelect } = props;
|
|
16
24
|
|
|
17
25
|
switch (id) {
|
|
18
26
|
case 'all': {
|
|
19
|
-
return <ProviderGrid />;
|
|
27
|
+
return <ProviderGrid onProviderSelect={onProviderSelect} />;
|
|
20
28
|
}
|
|
21
29
|
case 'azure': {
|
|
22
30
|
return <Azure />;
|
|
@@ -249,4 +249,29 @@ describe('createRemarkSelfClosingTagPlugin', () => {
|
|
|
249
249
|
|
|
250
250
|
expect(tree).toMatchSnapshot();
|
|
251
251
|
});
|
|
252
|
+
|
|
253
|
+
it('should handle tags wrapped in backticks (code)', () => {
|
|
254
|
+
const markdown = `Use this file: \`<${tagName} name="config.json" path="/app/config.json" />\` in your code.`;
|
|
255
|
+
const tree = processMarkdown(markdown, tagName);
|
|
256
|
+
|
|
257
|
+
expect(tree.children).toHaveLength(1);
|
|
258
|
+
expect(tree.children[0].type).toBe('paragraph');
|
|
259
|
+
|
|
260
|
+
const paragraphChildren = tree.children[0].children;
|
|
261
|
+
expect(paragraphChildren).toHaveLength(3);
|
|
262
|
+
|
|
263
|
+
expect(paragraphChildren[0].type).toBe('text');
|
|
264
|
+
expect(paragraphChildren[0].value).toBe('Use this file: ');
|
|
265
|
+
|
|
266
|
+
// The tag should be parsed even inside backticks
|
|
267
|
+
const tagNode = paragraphChildren[1];
|
|
268
|
+
expect(tagNode.type).toBe(tagName);
|
|
269
|
+
expect(tagNode.data?.hProperties).toEqual({
|
|
270
|
+
name: 'config.json',
|
|
271
|
+
path: '/app/config.json',
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
expect(paragraphChildren[2].type).toBe('text');
|
|
275
|
+
expect(paragraphChildren[2].value).toBe(' in your code.');
|
|
276
|
+
});
|
|
252
277
|
});
|
package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts
CHANGED
|
@@ -130,5 +130,33 @@ export const createRemarkSelfClosingTagPlugin =
|
|
|
130
130
|
return [SKIP, index + newChildren.length]; // Skip new nodes
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
|
+
|
|
134
|
+
// 3. Visit inlineCode nodes (backtick-wrapped tags like `<localFile ... />`)
|
|
135
|
+
// @ts-ignore
|
|
136
|
+
visit(tree, 'inlineCode', (node: any, index: number, parent) => {
|
|
137
|
+
log('>>> Visiting inlineCode node: "%s"', node.value);
|
|
138
|
+
|
|
139
|
+
if (!parent || typeof index !== 'number' || !node.value?.includes(`<${tagName}`)) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const match = node.value.match(exactTagRegex);
|
|
144
|
+
if (match) {
|
|
145
|
+
const [, attributesString] = match;
|
|
146
|
+
const properties = attributesString ? parseAttributes(attributesString.trim()) : {};
|
|
147
|
+
|
|
148
|
+
const newNode = {
|
|
149
|
+
data: {
|
|
150
|
+
hName: tagName,
|
|
151
|
+
hProperties: properties,
|
|
152
|
+
},
|
|
153
|
+
type: tagName,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
log('Replacing inlineCode node at index %d with %s node: %o', index, tagName, newNode);
|
|
157
|
+
parent.children.splice(index, 1, newNode);
|
|
158
|
+
return [SKIP, index + 1];
|
|
159
|
+
}
|
|
160
|
+
});
|
|
133
161
|
};
|
|
134
162
|
};
|