@lobehub/lobehub 2.1.14 → 2.1.15
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/CHANGELOG.md +25 -0
- package/changelog/v2.json +9 -0
- package/locales/en-US/discover.json +9 -0
- package/locales/zh-CN/discover.json +9 -0
- package/package.json +1 -1
- package/packages/types/src/discover/assistants.ts +1 -0
- package/packages/types/src/discover/index.ts +8 -0
- package/packages/utils/src/chunkers/trimBatchProbe/trimBatchProbe.ts +1 -1
- package/packages/utils/src/pricing.ts +6 -6
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx +3 -3
- package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +2 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/StatusFilter.tsx +36 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentList.tsx +69 -13
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserContent.tsx +0 -11
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupList.tsx +68 -14
- package/src/app/[variants]/(main)/community/(detail)/user/index.tsx +3 -1
- package/src/app/[variants]/(main)/community/(list)/agent/features/List/Item.tsx +2 -1
- package/src/locales/default/discover.ts +12 -0
- package/src/server/routers/lambda/market/social.ts +1 -1
- package/src/server/services/discover/index.ts +57 -2
- package/src/services/models.ts +0 -1
- package/src/services/social.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 2.1.15](https://github.com/lobehub/lobe-chat/compare/v2.1.14...v2.1.15)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-02-04**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Fixed the agents list the show updateAt time error.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Fixed the agents list the show updateAt time error, closes [#12103](https://github.com/lobehub/lobe-chat/issues/12103) ([3063cee](https://github.com/lobehub/lobe-chat/commit/3063cee))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
### [Version 2.1.14](https://github.com/lobehub/lobe-chat/compare/v2.1.13...v2.1.14)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2026-02-04**</sup>
|
package/changelog/v2.json
CHANGED
|
@@ -490,6 +490,15 @@
|
|
|
490
490
|
"user.noForkedAgentGroups": "No forked Agent Groups yet",
|
|
491
491
|
"user.noForkedAgents": "No forked Agents yet",
|
|
492
492
|
"user.publishedAgents": "Created Agents",
|
|
493
|
+
"user.publishedGroups": "Created Groups",
|
|
494
|
+
"user.searchPlaceholder": "Search by name or description...",
|
|
495
|
+
"user.statusFilter.all": "All",
|
|
496
|
+
"user.statusFilter.archived": "Archived",
|
|
497
|
+
"user.statusFilter.deprecated": "Deprecated",
|
|
498
|
+
"user.statusFilter.favorite": "Favorite",
|
|
499
|
+
"user.statusFilter.forked": "Forked",
|
|
500
|
+
"user.statusFilter.published": "Published",
|
|
501
|
+
"user.statusFilter.unpublished": "Under Review",
|
|
493
502
|
"user.tabs.favorites": "Favorites",
|
|
494
503
|
"user.tabs.forkedAgents": "Forked",
|
|
495
504
|
"user.tabs.publishedAgents": "Created",
|
|
@@ -490,6 +490,15 @@
|
|
|
490
490
|
"user.noForkedAgentGroups": "尚无已派生的代理组",
|
|
491
491
|
"user.noForkedAgents": "尚无已派生的代理",
|
|
492
492
|
"user.publishedAgents": "创作的助理",
|
|
493
|
+
"user.publishedGroups": "创作的群组",
|
|
494
|
+
"user.searchPlaceholder": "搜索名称或描述...",
|
|
495
|
+
"user.statusFilter.all": "全部",
|
|
496
|
+
"user.statusFilter.archived": "已归档",
|
|
497
|
+
"user.statusFilter.deprecated": "已废弃",
|
|
498
|
+
"user.statusFilter.favorite": "已收藏",
|
|
499
|
+
"user.statusFilter.forked": "已派生",
|
|
500
|
+
"user.statusFilter.published": "已发布",
|
|
501
|
+
"user.statusFilter.unpublished": "审核中",
|
|
493
502
|
"user.tabs.favorites": "收藏",
|
|
494
503
|
"user.tabs.forkedAgents": "已派生",
|
|
495
504
|
"user.tabs.publishedAgents": "创作",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.15",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -67,6 +67,14 @@ export interface DiscoverUserInfo {
|
|
|
67
67
|
export interface DiscoverUserProfile {
|
|
68
68
|
agentGroups?: DiscoverGroupAgentItem[];
|
|
69
69
|
agents: DiscoverAssistantItem[];
|
|
70
|
+
/**
|
|
71
|
+
* Agent groups favorited by the user
|
|
72
|
+
*/
|
|
73
|
+
favoriteAgentGroups?: DiscoverGroupAgentItem[];
|
|
74
|
+
/**
|
|
75
|
+
* Agents favorited by the user
|
|
76
|
+
*/
|
|
77
|
+
favoriteAgents?: DiscoverAssistantItem[];
|
|
70
78
|
/**
|
|
71
79
|
* Agent groups forked by the user
|
|
72
80
|
*/
|
|
@@ -202,7 +202,7 @@ export const handleSingle = async (
|
|
|
202
202
|
* to avoid breaking structured XML/JSON-like content mid-way.
|
|
203
203
|
*
|
|
204
204
|
* Bisection example (8 segments, keep newest):
|
|
205
|
-
* try 4 (fits?)
|
|
205
|
+
* try 4 (fits?) -> yes -> try 6 -> no -> try 5 -> yes => best=5
|
|
206
206
|
* if compact retry needed, repeat with build(true) and pick the better fit.
|
|
207
207
|
*
|
|
208
208
|
* This minimizes structural breakage by preferring whole built segments and only truncating the last one as a last resort.
|
|
@@ -2,9 +2,9 @@ import { Pricing, PricingUnit, PricingUnitName } from 'model-bank';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Internal helper to extract the displayed unit rate from a pricing unit by strategy
|
|
5
|
-
* - fixed
|
|
6
|
-
* - tiered
|
|
7
|
-
* - lookup
|
|
5
|
+
* - fixed: rate
|
|
6
|
+
* - tiered: tiers[0].rate
|
|
7
|
+
* - lookup: first price value
|
|
8
8
|
*/
|
|
9
9
|
const getRateFromUnit = (unit: PricingUnit): number | undefined => {
|
|
10
10
|
switch (unit.strategy) {
|
|
@@ -39,9 +39,9 @@ export const getUnitRateByName = (
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Get text input unit rate from pricing
|
|
42
|
-
* - fixed
|
|
43
|
-
* - tiered
|
|
44
|
-
* - lookup
|
|
42
|
+
* - fixed: rate
|
|
43
|
+
* - tiered: tiers[0].rate
|
|
44
|
+
* - lookup: Object.values(lookup.prices)[0]
|
|
45
45
|
*/
|
|
46
46
|
export function getTextInputUnitRate(pricing?: Pricing): number | undefined {
|
|
47
47
|
return getUnitRateByName(pricing, 'textInput');
|
|
@@ -75,7 +75,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
|
|
75
75
|
// Fetch favorite status
|
|
76
76
|
const { data: favoriteStatus, mutate: mutateFavorite } = useSWR(
|
|
77
77
|
identifier && isAuthenticated ? ['favorite-status', 'agent', identifier] : null,
|
|
78
|
-
() => socialService.checkFavoriteStatus('agent', identifier!),
|
|
78
|
+
() => socialService.checkFavoriteStatus('agent-group', identifier!),
|
|
79
79
|
{ revalidateOnFocus: false },
|
|
80
80
|
);
|
|
81
81
|
|
|
@@ -100,10 +100,10 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
|
|
100
100
|
setFavoriteLoading(true);
|
|
101
101
|
try {
|
|
102
102
|
if (isFavorited) {
|
|
103
|
-
await socialService.removeFavorite('agent', identifier);
|
|
103
|
+
await socialService.removeFavorite('agent-group', identifier);
|
|
104
104
|
message.success(t('assistant.unfavoriteSuccess'));
|
|
105
105
|
} else {
|
|
106
|
-
await socialService.addFavorite('agent', identifier);
|
|
106
|
+
await socialService.addFavorite('agent-group', identifier);
|
|
107
107
|
message.success(t('assistant.favoriteSuccess'));
|
|
108
108
|
}
|
|
109
109
|
await mutateFavorite();
|
|
@@ -13,6 +13,8 @@ export interface UserDetailContextConfig {
|
|
|
13
13
|
agentCount: number;
|
|
14
14
|
agentGroups?: DiscoverGroupAgentItem[];
|
|
15
15
|
agents: DiscoverAssistantItem[];
|
|
16
|
+
favoriteAgentGroups?: DiscoverGroupAgentItem[];
|
|
17
|
+
favoriteAgents?: DiscoverAssistantItem[];
|
|
16
18
|
forkedAgentGroups?: DiscoverGroupAgentItem[];
|
|
17
19
|
forkedAgents?: DiscoverAssistantItem[];
|
|
18
20
|
groupCount: number;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Select } from 'antd';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
export type StatusFilterValue = 'published' | 'unpublished' | 'deprecated' | 'archived' | 'forked' | 'favorite';
|
|
8
|
+
|
|
9
|
+
interface StatusFilterProps {
|
|
10
|
+
onChange: (value: StatusFilterValue) => void;
|
|
11
|
+
value: StatusFilterValue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const StatusFilter = memo<StatusFilterProps>(({ value, onChange }) => {
|
|
15
|
+
const { t } = useTranslation('discover');
|
|
16
|
+
|
|
17
|
+
const options = [
|
|
18
|
+
{ label: t('user.statusFilter.published'), value: 'published' as const },
|
|
19
|
+
{ label: t('user.statusFilter.unpublished'), value: 'unpublished' as const },
|
|
20
|
+
{ label: t('user.statusFilter.deprecated'), value: 'deprecated' as const },
|
|
21
|
+
{ label: t('user.statusFilter.archived'), value: 'archived' as const },
|
|
22
|
+
{ label: t('user.statusFilter.forked'), value: 'forked' as const },
|
|
23
|
+
{ label: t('user.statusFilter.favorite'), value: 'favorite' as const },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Select
|
|
28
|
+
onChange={onChange}
|
|
29
|
+
options={options}
|
|
30
|
+
style={{ minWidth: 120 }}
|
|
31
|
+
value={value}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default StatusFilter;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Flexbox, Grid, Tag, Text } from '@lobehub/ui';
|
|
4
|
-
import { Pagination } from 'antd';
|
|
4
|
+
import { Input, Pagination } from 'antd';
|
|
5
5
|
import { memo, useMemo, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
8
|
import AssistantEmpty from '../../../features/AssistantEmpty';
|
|
9
9
|
import { useUserDetailContext } from './DetailProvider';
|
|
10
|
+
import StatusFilter, { type StatusFilterValue } from './StatusFilter';
|
|
10
11
|
import UserAgentCard from './UserAgentCard';
|
|
11
12
|
|
|
12
13
|
interface UserAgentListProps {
|
|
@@ -14,27 +15,82 @@ interface UserAgentListProps {
|
|
|
14
15
|
rows?: number;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
const UserAgentList = memo<UserAgentListProps>(({ rows = 4, pageSize =
|
|
18
|
+
const UserAgentList = memo<UserAgentListProps>(({ rows = 4, pageSize = 8 }) => {
|
|
18
19
|
const { t } = useTranslation('discover');
|
|
19
|
-
const { agents, agentCount } = useUserDetailContext();
|
|
20
|
+
const { agents, agentCount, forkedAgents = [], favoriteAgents = [], isOwner } = useUserDetailContext();
|
|
20
21
|
const [currentPage, setCurrentPage] = useState(1);
|
|
22
|
+
const [statusFilter, setStatusFilter] = useState<StatusFilterValue>('published');
|
|
23
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
24
|
+
|
|
25
|
+
// Combine agents and forked agents, then filter based on status and search
|
|
26
|
+
const filteredAgents = useMemo(() => {
|
|
27
|
+
let allAgents = [...agents];
|
|
28
|
+
|
|
29
|
+
if (statusFilter === 'forked') {
|
|
30
|
+
// Show only forked agents (those with forkedFromAgentId)
|
|
31
|
+
allAgents = forkedAgents;
|
|
32
|
+
} else if (statusFilter === 'favorite') {
|
|
33
|
+
// Show only favorited agents
|
|
34
|
+
allAgents = favoriteAgents;
|
|
35
|
+
} else {
|
|
36
|
+
// Filter by status for non-forked agents
|
|
37
|
+
allAgents = allAgents.filter((agent) => {
|
|
38
|
+
return agent.status === statusFilter;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Apply search filter
|
|
43
|
+
if (searchQuery.trim()) {
|
|
44
|
+
const query = searchQuery.toLowerCase();
|
|
45
|
+
allAgents = allAgents.filter((agent) => {
|
|
46
|
+
console.log('agent', agent);
|
|
47
|
+
const name = agent?.title?.toLowerCase() || '';
|
|
48
|
+
const description = agent?.description?.toLowerCase() || '';
|
|
49
|
+
return name.includes(query) || description.includes(query);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return allAgents;
|
|
54
|
+
}, [agents, forkedAgents, statusFilter, searchQuery]);
|
|
21
55
|
|
|
22
56
|
const paginatedAgents = useMemo(() => {
|
|
23
57
|
const startIndex = (currentPage - 1) * pageSize;
|
|
24
|
-
return
|
|
25
|
-
}, [
|
|
58
|
+
return filteredAgents.slice(startIndex, startIndex + pageSize);
|
|
59
|
+
}, [filteredAgents, currentPage, pageSize]);
|
|
60
|
+
|
|
61
|
+
// Reset to page 1 when filter or search changes
|
|
62
|
+
useMemo(() => {
|
|
63
|
+
setCurrentPage(1);
|
|
64
|
+
}, [statusFilter, searchQuery]);
|
|
26
65
|
|
|
27
|
-
if (agents.length === 0) return <AssistantEmpty />;
|
|
66
|
+
if (agents.length === 0 && forkedAgents.length === 0) return <AssistantEmpty />;
|
|
28
67
|
|
|
29
|
-
const showPagination =
|
|
68
|
+
const showPagination = filteredAgents.length > pageSize;
|
|
30
69
|
|
|
31
70
|
return (
|
|
32
71
|
<Flexbox gap={16}>
|
|
33
|
-
<Flexbox align={'center'} gap={8} horizontal>
|
|
34
|
-
<
|
|
35
|
-
{
|
|
36
|
-
|
|
37
|
-
|
|
72
|
+
<Flexbox align={'center'} gap={8} horizontal justify={'space-between'}>
|
|
73
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
74
|
+
<Text fontSize={16} weight={500}>
|
|
75
|
+
{t('user.publishedAgents')}
|
|
76
|
+
</Text>
|
|
77
|
+
{agentCount > 0 && <Tag>{filteredAgents.length}</Tag>}
|
|
78
|
+
</Flexbox>
|
|
79
|
+
{isOwner && (
|
|
80
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
81
|
+
<Input.Search
|
|
82
|
+
allowClear
|
|
83
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
84
|
+
placeholder={t('user.searchPlaceholder')}
|
|
85
|
+
style={{ width: 200 }}
|
|
86
|
+
value={searchQuery}
|
|
87
|
+
/>
|
|
88
|
+
<StatusFilter
|
|
89
|
+
onChange={(value) => setStatusFilter(value)}
|
|
90
|
+
value={statusFilter}
|
|
91
|
+
/>
|
|
92
|
+
</Flexbox>
|
|
93
|
+
)}
|
|
38
94
|
</Flexbox>
|
|
39
95
|
<Grid rows={rows} width={'100%'}>
|
|
40
96
|
{paginatedAgents.map((item, index) => (
|
|
@@ -48,7 +104,7 @@ const UserAgentList = memo<UserAgentListProps>(({ rows = 4, pageSize = 10 }) =>
|
|
|
48
104
|
onChange={(page) => setCurrentPage(page)}
|
|
49
105
|
pageSize={pageSize}
|
|
50
106
|
showSizeChanger={false}
|
|
51
|
-
total={
|
|
107
|
+
total={filteredAgents.length}
|
|
52
108
|
/>
|
|
53
109
|
</Flexbox>
|
|
54
110
|
)}
|
|
@@ -3,25 +3,14 @@
|
|
|
3
3
|
import { Flexbox } from '@lobehub/ui';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
|
|
6
|
-
import { useUserDetailContext } from './DetailProvider';
|
|
7
6
|
import UserAgentList from './UserAgentList';
|
|
8
|
-
import UserFavoriteAgents from './UserFavoriteAgents';
|
|
9
|
-
import UserFavoritePlugins from './UserFavoritePlugins';
|
|
10
|
-
import UserForkedAgentGroups from './UserForkedAgentGroups';
|
|
11
|
-
import UserForkedAgents from './UserForkedAgents';
|
|
12
7
|
import UserGroupList from './UserGroupList';
|
|
13
8
|
|
|
14
9
|
const UserContent = memo(() => {
|
|
15
|
-
const { forkedAgents, forkedAgentGroups } = useUserDetailContext();
|
|
16
|
-
|
|
17
10
|
return (
|
|
18
11
|
<Flexbox gap={32}>
|
|
19
12
|
<UserAgentList />
|
|
20
13
|
<UserGroupList />
|
|
21
|
-
<UserForkedAgents agents={forkedAgents} />
|
|
22
|
-
<UserForkedAgentGroups agentGroups={forkedAgentGroups} />
|
|
23
|
-
<UserFavoriteAgents />
|
|
24
|
-
<UserFavoritePlugins />
|
|
25
14
|
</Flexbox>
|
|
26
15
|
);
|
|
27
16
|
});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Flexbox, Grid, Tag, Text } from '@lobehub/ui';
|
|
4
|
-
import { Pagination } from 'antd';
|
|
4
|
+
import { Input, Pagination } from 'antd';
|
|
5
5
|
import { memo, useMemo, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
8
|
import { useUserDetailContext } from './DetailProvider';
|
|
9
|
+
import StatusFilter, { type StatusFilterValue } from './StatusFilter';
|
|
9
10
|
import UserGroupCard from './UserGroupCard';
|
|
10
11
|
|
|
11
12
|
interface UserGroupListProps {
|
|
@@ -13,28 +14,81 @@ interface UserGroupListProps {
|
|
|
13
14
|
rows?: number;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const UserGroupList = memo<UserGroupListProps>(({ rows = 4, pageSize =
|
|
17
|
+
const UserGroupList = memo<UserGroupListProps>(({ rows = 4, pageSize = 8 }) => {
|
|
17
18
|
const { t } = useTranslation('discover');
|
|
18
|
-
const { agentGroups, groupCount } = useUserDetailContext();
|
|
19
|
+
const { agentGroups = [], groupCount, forkedAgentGroups = [], favoriteAgentGroups = [], isOwner } = useUserDetailContext();
|
|
19
20
|
const [currentPage, setCurrentPage] = useState(1);
|
|
21
|
+
const [statusFilter, setStatusFilter] = useState<StatusFilterValue>('published');
|
|
22
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
23
|
+
|
|
24
|
+
// Combine groups and forked groups, then filter based on status and search
|
|
25
|
+
const filteredGroups = useMemo(() => {
|
|
26
|
+
let allGroups = [...agentGroups];
|
|
27
|
+
|
|
28
|
+
if (statusFilter === 'forked') {
|
|
29
|
+
// Show only forked groups (those with forkedFromAgentId)
|
|
30
|
+
allGroups = forkedAgentGroups;
|
|
31
|
+
} else if (statusFilter === 'favorite') {
|
|
32
|
+
// Show only favorited groups
|
|
33
|
+
allGroups = favoriteAgentGroups;
|
|
34
|
+
} else {
|
|
35
|
+
// Filter by status for non-forked groups
|
|
36
|
+
allGroups = allGroups.filter((group) => {
|
|
37
|
+
return group.status === statusFilter;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Apply search filter
|
|
42
|
+
if (searchQuery.trim()) {
|
|
43
|
+
const query = searchQuery.toLowerCase();
|
|
44
|
+
allGroups = allGroups.filter((group) => {
|
|
45
|
+
const name = group?.title?.toLowerCase() || '';
|
|
46
|
+
const description = group?.description?.toLowerCase() || '';
|
|
47
|
+
return name.includes(query) || description.includes(query);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return allGroups;
|
|
52
|
+
}, [agentGroups, forkedAgentGroups, statusFilter, searchQuery]);
|
|
20
53
|
|
|
21
54
|
const paginatedGroups = useMemo(() => {
|
|
22
|
-
if (!agentGroups) return [];
|
|
23
55
|
const startIndex = (currentPage - 1) * pageSize;
|
|
24
|
-
return
|
|
25
|
-
}, [
|
|
56
|
+
return filteredGroups.slice(startIndex, startIndex + pageSize);
|
|
57
|
+
}, [filteredGroups, currentPage, pageSize]);
|
|
58
|
+
|
|
59
|
+
// Reset to page 1 when filter or search changes
|
|
60
|
+
useMemo(() => {
|
|
61
|
+
setCurrentPage(1);
|
|
62
|
+
}, [statusFilter, searchQuery]);
|
|
26
63
|
|
|
27
|
-
if (
|
|
64
|
+
if (agentGroups.length === 0 && forkedAgentGroups.length === 0) return null;
|
|
28
65
|
|
|
29
|
-
const showPagination =
|
|
66
|
+
const showPagination = filteredGroups.length > pageSize;
|
|
30
67
|
|
|
31
68
|
return (
|
|
32
69
|
<Flexbox gap={16}>
|
|
33
|
-
<Flexbox align={'center'} gap={8} horizontal>
|
|
34
|
-
<
|
|
35
|
-
{
|
|
36
|
-
|
|
37
|
-
|
|
70
|
+
<Flexbox align={'center'} gap={8} horizontal justify={'space-between'}>
|
|
71
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
72
|
+
<Text fontSize={16} weight={500}>
|
|
73
|
+
{t('user.publishedGroups', { defaultValue: '创作的群组' })}
|
|
74
|
+
</Text>
|
|
75
|
+
{groupCount > 0 && <Tag>{filteredGroups.length}</Tag>}
|
|
76
|
+
</Flexbox>
|
|
77
|
+
{isOwner && (
|
|
78
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
79
|
+
<Input.Search
|
|
80
|
+
allowClear
|
|
81
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
82
|
+
placeholder={t('user.searchPlaceholder')}
|
|
83
|
+
style={{ width: 200 }}
|
|
84
|
+
value={searchQuery}
|
|
85
|
+
/>
|
|
86
|
+
<StatusFilter
|
|
87
|
+
onChange={(value) => setStatusFilter(value)}
|
|
88
|
+
value={statusFilter}
|
|
89
|
+
/>
|
|
90
|
+
</Flexbox>
|
|
91
|
+
)}
|
|
38
92
|
</Flexbox>
|
|
39
93
|
<Grid rows={rows} width={'100%'}>
|
|
40
94
|
{paginatedGroups.map((item, index) => (
|
|
@@ -48,7 +102,7 @@ const UserGroupList = memo<UserGroupListProps>(({ rows = 4, pageSize = 10 }) =>
|
|
|
48
102
|
onChange={(page) => setCurrentPage(page)}
|
|
49
103
|
pageSize={pageSize}
|
|
50
104
|
showSizeChanger={false}
|
|
51
|
-
total={
|
|
105
|
+
total={filteredGroups.length}
|
|
52
106
|
/>
|
|
53
107
|
</Flexbox>
|
|
54
108
|
)}
|
|
@@ -61,12 +61,14 @@ const UserDetailPage = memo<UserDetailPageProps>(({ mobile }) => {
|
|
|
61
61
|
|
|
62
62
|
const contextConfig = useMemo(() => {
|
|
63
63
|
if (!data || !data.user) return null;
|
|
64
|
-
const { user, agents, agentGroups, forkedAgents, forkedAgentGroups } = data;
|
|
64
|
+
const { user, agents, agentGroups, forkedAgents, forkedAgentGroups, favoriteAgents, favoriteAgentGroups } = data;
|
|
65
65
|
const totalInstalls = agents.reduce((sum, agent) => sum + (agent.installCount || 0), 0);
|
|
66
66
|
return {
|
|
67
67
|
agentCount: agents.length,
|
|
68
68
|
agentGroups: agentGroups || [],
|
|
69
69
|
agents,
|
|
70
|
+
favoriteAgentGroups: favoriteAgentGroups || [],
|
|
71
|
+
favoriteAgents: favoriteAgents || [],
|
|
70
72
|
forkedAgentGroups: forkedAgentGroups || [],
|
|
71
73
|
forkedAgents: forkedAgents || [],
|
|
72
74
|
groupCount: agentGroups?.length || 0,
|
|
@@ -56,6 +56,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
|
|
|
56
56
|
const AssistantItem = memo<DiscoverAssistantItem>(
|
|
57
57
|
({
|
|
58
58
|
createdAt,
|
|
59
|
+
updatedAt,
|
|
59
60
|
author,
|
|
60
61
|
avatar,
|
|
61
62
|
title,
|
|
@@ -225,7 +226,7 @@ const AssistantItem = memo<DiscoverAssistantItem>(
|
|
|
225
226
|
<Icon icon={ClockIcon} size={14} />
|
|
226
227
|
<PublishedTime
|
|
227
228
|
className={styles.secondaryDesc}
|
|
228
|
-
date={createdAt}
|
|
229
|
+
date={updatedAt || createdAt}
|
|
229
230
|
template={'MMM DD, YYYY'}
|
|
230
231
|
/>
|
|
231
232
|
</Flexbox>
|
|
@@ -891,6 +891,18 @@ export default {
|
|
|
891
891
|
|
|
892
892
|
'user.publishedAgents': 'Created Agents',
|
|
893
893
|
|
|
894
|
+
'user.publishedGroups': 'Created Groups',
|
|
895
|
+
|
|
896
|
+
'user.searchPlaceholder': 'Search by name or description...',
|
|
897
|
+
|
|
898
|
+
'user.statusFilter.all': 'All',
|
|
899
|
+
'user.statusFilter.archived': 'Archived',
|
|
900
|
+
'user.statusFilter.deprecated': 'Deprecated',
|
|
901
|
+
'user.statusFilter.favorite': 'Favorite',
|
|
902
|
+
'user.statusFilter.forked': 'Forked',
|
|
903
|
+
'user.statusFilter.published': 'Published',
|
|
904
|
+
'user.statusFilter.unpublished': 'Under Review',
|
|
905
|
+
|
|
894
906
|
'user.tabs.favorites': 'Favorites',
|
|
895
907
|
|
|
896
908
|
'user.tabs.forkedAgents': 'Forked',
|
|
@@ -17,7 +17,7 @@ const socialPublicProcedure = publicProcedure
|
|
|
17
17
|
.use(marketSDK);
|
|
18
18
|
|
|
19
19
|
// Schema definitions
|
|
20
|
-
const targetTypeSchema = z.enum(['agent', 'plugin']);
|
|
20
|
+
const targetTypeSchema = z.enum(['agent', 'plugin', 'agent-group']);
|
|
21
21
|
|
|
22
22
|
const paginationSchema = z.object({
|
|
23
23
|
limit: z.number().optional(),
|
|
@@ -745,6 +745,7 @@ export class DiscoverService {
|
|
|
745
745
|
title: item.name || item.identifier,
|
|
746
746
|
tokenUsage: item.tokenUsage || 0,
|
|
747
747
|
type: item.type,
|
|
748
|
+
updatedAt: item.updatedAt,
|
|
748
749
|
userName: normalizedAuthor.userName,
|
|
749
750
|
};
|
|
750
751
|
});
|
|
@@ -1710,6 +1711,8 @@ export class DiscoverService {
|
|
|
1710
1711
|
locale,
|
|
1711
1712
|
})) as UserInfoResponse & {
|
|
1712
1713
|
agentGroups?: any[];
|
|
1714
|
+
favoriteAgentGroups?: any[];
|
|
1715
|
+
favoriteAgents?: any[];
|
|
1713
1716
|
forkedAgentGroups?: any[];
|
|
1714
1717
|
forkedAgents?: any[];
|
|
1715
1718
|
};
|
|
@@ -1719,7 +1722,7 @@ export class DiscoverService {
|
|
|
1719
1722
|
return undefined;
|
|
1720
1723
|
}
|
|
1721
1724
|
|
|
1722
|
-
const { user, agents, agentGroups, forkedAgents, forkedAgentGroups } = response;
|
|
1725
|
+
const { user, agents, agentGroups, forkedAgents, forkedAgentGroups, favoriteAgents, favoriteAgentGroups } = response;
|
|
1723
1726
|
|
|
1724
1727
|
// Transform agents to DiscoverAssistantItem format
|
|
1725
1728
|
const transformedAgents: DiscoverAssistantItem[] = (agents || []).map((agent: any) => ({
|
|
@@ -1811,9 +1814,59 @@ export class DiscoverService {
|
|
|
1811
1814
|
updatedAt: group.updatedAt,
|
|
1812
1815
|
}));
|
|
1813
1816
|
|
|
1817
|
+
// Transform favoriteAgents to DiscoverAssistantItem format
|
|
1818
|
+
const transformedFavoriteAgents: DiscoverAssistantItem[] = (favoriteAgents || []).map(
|
|
1819
|
+
(agent: any) => ({
|
|
1820
|
+
author: agent.author || '',
|
|
1821
|
+
avatar: agent.avatar || '',
|
|
1822
|
+
category: agent.category as any,
|
|
1823
|
+
config: {} as any,
|
|
1824
|
+
createdAt: agent.createdAt,
|
|
1825
|
+
description: agent.description || '',
|
|
1826
|
+
forkCount: agent.forkCount || 0,
|
|
1827
|
+
forkedFromAgentId: agent.forkedFromAgentId || null,
|
|
1828
|
+
homepage: `https://lobehub.com/discover/assistant/${agent.identifier}`,
|
|
1829
|
+
identifier: agent.identifier,
|
|
1830
|
+
installCount: agent.installCount,
|
|
1831
|
+
isValidated: agent.isValidated,
|
|
1832
|
+
knowledgeCount: agent.knowledgeCount || 0,
|
|
1833
|
+
pluginCount: agent.pluginCount || 0,
|
|
1834
|
+
schemaVersion: 1,
|
|
1835
|
+
status: agent.status,
|
|
1836
|
+
tags: agent.tags || [],
|
|
1837
|
+
title: agent.name || agent.identifier,
|
|
1838
|
+
tokenUsage: agent.tokenUsage || 0,
|
|
1839
|
+
}),
|
|
1840
|
+
);
|
|
1841
|
+
|
|
1842
|
+
// Transform favoriteAgentGroups to DiscoverGroupAgentItem format
|
|
1843
|
+
const transformedFavoriteAgentGroups = (favoriteAgentGroups || []).map((group: any) => ({
|
|
1844
|
+
author: group.author || '',
|
|
1845
|
+
avatar: group.avatar || '👥',
|
|
1846
|
+
category: group.category as any,
|
|
1847
|
+
createdAt: group.createdAt,
|
|
1848
|
+
description: group.description || '',
|
|
1849
|
+
forkCount: group.forkCount || 0,
|
|
1850
|
+
forkedFromGroupId: group.forkedFromGroupId || null,
|
|
1851
|
+
homepage: `https://lobehub.com/discover/group_agent/${group.identifier}`,
|
|
1852
|
+
identifier: group.identifier,
|
|
1853
|
+
installCount: group.installCount || 0,
|
|
1854
|
+
isFeatured: group.isFeatured || false,
|
|
1855
|
+
isOfficial: group.isOfficial || false,
|
|
1856
|
+
isValidated: group.isValidated,
|
|
1857
|
+
memberCount: 0, // Will be populated from memberAgents in detail view
|
|
1858
|
+
schemaVersion: 1,
|
|
1859
|
+
status: group.status,
|
|
1860
|
+
tags: group.tags || [],
|
|
1861
|
+
title: group.name || group.identifier,
|
|
1862
|
+
updatedAt: group.updatedAt,
|
|
1863
|
+
}));
|
|
1864
|
+
|
|
1814
1865
|
const result: DiscoverUserProfile = {
|
|
1815
1866
|
agentGroups: transformedAgentGroups,
|
|
1816
1867
|
agents: transformedAgents,
|
|
1868
|
+
favoriteAgentGroups: transformedFavoriteAgentGroups,
|
|
1869
|
+
favoriteAgents: transformedFavoriteAgents,
|
|
1817
1870
|
forkedAgentGroups: transformedForkedAgentGroups,
|
|
1818
1871
|
forkedAgents: transformedForkedAgents,
|
|
1819
1872
|
user: {
|
|
@@ -1833,11 +1886,13 @@ export class DiscoverService {
|
|
|
1833
1886
|
};
|
|
1834
1887
|
|
|
1835
1888
|
log(
|
|
1836
|
-
'getUserInfo: returning user profile with %d agents, %d groups, %d forked agents, %d forked groups',
|
|
1889
|
+
'getUserInfo: returning user profile with %d agents, %d groups, %d forked agents, %d forked groups, %d favorite agents, %d favorite groups',
|
|
1837
1890
|
result.agents.length,
|
|
1838
1891
|
result.agentGroups?.length || 0,
|
|
1839
1892
|
result.forkedAgents?.length || 0,
|
|
1840
1893
|
result.forkedAgentGroups?.length || 0,
|
|
1894
|
+
result.favoriteAgents?.length || 0,
|
|
1895
|
+
result.favoriteAgentGroups?.length || 0,
|
|
1841
1896
|
);
|
|
1842
1897
|
return result;
|
|
1843
1898
|
} catch (error) {
|
package/src/services/models.ts
CHANGED
|
@@ -75,7 +75,6 @@ export class ModelsService {
|
|
|
75
75
|
const runtimeProvider = resolveRuntimeProvider(provider);
|
|
76
76
|
const enableFetchOnClient = isEnableFetchOnClient(provider);
|
|
77
77
|
|
|
78
|
-
console.log('enableFetchOnClient:', enableFetchOnClient);
|
|
79
78
|
let res: Response;
|
|
80
79
|
if (enableFetchOnClient) {
|
|
81
80
|
const agentRuntime = await initializeWithClientStore({
|
package/src/services/social.ts
CHANGED