@lobehub/lobehub 2.0.0-next.296 → 2.0.0-next.298
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 +50 -0
- package/changelog/v1.json +18 -0
- package/package.json +2 -2
- package/packages/types/package.json +1 -1
- package/packages/types/src/discover/assistants.ts +4 -0
- package/packages/types/src/discover/groupAgents.ts +196 -0
- package/packages/types/src/discover/index.ts +5 -1
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/DetailProvider.tsx +19 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Members/index.tsx +137 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Nav.tsx +87 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Overview/index.tsx +213 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Related/index.tsx +89 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/TagList.tsx +20 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/index.tsx +71 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Versions/index.tsx +119 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/index.tsx +51 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx +253 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +222 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/index.tsx +34 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/Summary/index.tsx +42 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/index.tsx +41 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/StatusPage/index.tsx +104 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/index.tsx +103 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/loading.tsx +1 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +7 -1
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserContent.tsx +2 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +186 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupList.tsx +59 -0
- package/src/app/[variants]/(main)/community/(detail)/user/index.tsx +3 -1
- package/src/app/[variants]/(main)/community/(list)/assistant/features/List/Item.tsx +26 -8
- package/src/app/[variants]/(main)/community/(list)/assistant/index.tsx +1 -0
- package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +2 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +2 -1
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupForkConfirmModal.tsx +60 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupPublishResultModal.tsx +62 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/PublishButton.tsx +122 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/index.tsx +46 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/types.ts +12 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/useMarketGroupPublish.ts +211 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/utils.ts +22 -0
- package/src/app/[variants]/(main)/home/_layout/HomeAgentIdSync.tsx +23 -0
- package/src/app/[variants]/(main)/home/_layout/index.tsx +2 -0
- package/src/app/[variants]/router/desktopRouter.config.tsx +7 -0
- package/src/locales/default/setting.ts +12 -0
- package/src/server/routers/lambda/market/agentGroup.ts +296 -0
- package/src/server/routers/lambda/market/index.ts +134 -4
- package/src/server/services/discover/index.ts +123 -7
- package/src/services/discover.ts +58 -1
- package/src/store/discover/slices/groupAgent/action.ts +80 -0
- package/src/store/discover/store.ts +3 -0
- package/src/store/tool/slices/lobehubSkillStore/action.ts +1 -2
package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/PublishButton.tsx
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Button } from '@lobehub/ui';
|
|
2
|
+
import { ShapesUploadIcon } from '@lobehub/ui/icons';
|
|
3
|
+
import { memo, useCallback, useMemo, useState } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
|
|
6
|
+
import { message } from '@/components/AntdStaticMethods';
|
|
7
|
+
import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
|
|
8
|
+
import { resolveMarketAuthError } from '@/layout/AuthProvider/MarketAuth/errors';
|
|
9
|
+
|
|
10
|
+
import GroupForkConfirmModal from './GroupForkConfirmModal';
|
|
11
|
+
import type { MarketPublishAction, OriginalGroupInfo } from './types';
|
|
12
|
+
import { useMarketGroupPublish } from './useMarketGroupPublish';
|
|
13
|
+
|
|
14
|
+
interface GroupPublishButtonProps {
|
|
15
|
+
action: MarketPublishAction;
|
|
16
|
+
onPublishSuccess?: (identifier: string) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const PublishButton = memo<GroupPublishButtonProps>(({ action, onPublishSuccess }) => {
|
|
20
|
+
const { t } = useTranslation(['setting', 'marketAuth']);
|
|
21
|
+
|
|
22
|
+
const { isAuthenticated, isLoading, signIn } = useMarketAuth();
|
|
23
|
+
const { checkOwnership, isCheckingOwnership, isPublishing, publish } = useMarketGroupPublish({
|
|
24
|
+
action,
|
|
25
|
+
onSuccess: onPublishSuccess,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Fork confirmation modal state
|
|
29
|
+
const [showForkModal, setShowForkModal] = useState(false);
|
|
30
|
+
const [originalGroupInfo, setOriginalGroupInfo] = useState<OriginalGroupInfo | null>(null);
|
|
31
|
+
|
|
32
|
+
const buttonConfig = useMemo(() => {
|
|
33
|
+
if (action === 'upload') {
|
|
34
|
+
return {
|
|
35
|
+
authenticated: t('marketPublish.uploadGroup.tooltip'),
|
|
36
|
+
unauthenticated: t('marketPublish.uploadGroup.tooltip'),
|
|
37
|
+
} as const;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const submitText = t('submitGroupModal.tooltips');
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
authenticated: submitText,
|
|
44
|
+
unauthenticated: t('marketPublish.submitGroup.tooltip'),
|
|
45
|
+
} as const;
|
|
46
|
+
}, [action, t]);
|
|
47
|
+
|
|
48
|
+
const doPublish = useCallback(async () => {
|
|
49
|
+
// Check ownership before publishing
|
|
50
|
+
const { needsForkConfirm, originalGroup } = await checkOwnership();
|
|
51
|
+
|
|
52
|
+
if (needsForkConfirm && originalGroup) {
|
|
53
|
+
// Show fork confirmation modal
|
|
54
|
+
setOriginalGroupInfo(originalGroup);
|
|
55
|
+
setShowForkModal(true);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// No confirmation needed, proceed with publish
|
|
60
|
+
await publish();
|
|
61
|
+
}, [checkOwnership, publish]);
|
|
62
|
+
|
|
63
|
+
const handleButtonClick = useCallback(async () => {
|
|
64
|
+
if (!isAuthenticated) {
|
|
65
|
+
try {
|
|
66
|
+
await signIn();
|
|
67
|
+
// After authentication, proceed with ownership check and publish
|
|
68
|
+
await doPublish();
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`[GroupPublishButton][${action}] Authorization failed:`, error);
|
|
71
|
+
const normalizedError = resolveMarketAuthError(error);
|
|
72
|
+
message.error({
|
|
73
|
+
content: t(`errors.${normalizedError.code}`, { ns: 'marketAuth' }),
|
|
74
|
+
key: 'market-auth',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// User is authenticated, check ownership and publish
|
|
81
|
+
await doPublish();
|
|
82
|
+
}, [action, doPublish, isAuthenticated, signIn, t]);
|
|
83
|
+
|
|
84
|
+
const handleForkConfirm = useCallback(async () => {
|
|
85
|
+
setShowForkModal(false);
|
|
86
|
+
setOriginalGroupInfo(null);
|
|
87
|
+
// User confirmed, proceed with publish
|
|
88
|
+
await publish();
|
|
89
|
+
}, [publish]);
|
|
90
|
+
|
|
91
|
+
const handleForkCancel = useCallback(() => {
|
|
92
|
+
setShowForkModal(false);
|
|
93
|
+
setOriginalGroupInfo(null);
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
const buttonTitle = isAuthenticated ? buttonConfig.authenticated : buttonConfig.unauthenticated;
|
|
97
|
+
const loading = isLoading || isCheckingOwnership || isPublishing;
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<>
|
|
101
|
+
<Button
|
|
102
|
+
icon={ShapesUploadIcon}
|
|
103
|
+
loading={loading}
|
|
104
|
+
onClick={handleButtonClick}
|
|
105
|
+
title={buttonTitle}
|
|
106
|
+
>
|
|
107
|
+
{t('publishToCommunity')}
|
|
108
|
+
</Button>
|
|
109
|
+
<GroupForkConfirmModal
|
|
110
|
+
loading={isPublishing}
|
|
111
|
+
onCancel={handleForkCancel}
|
|
112
|
+
onConfirm={handleForkConfirm}
|
|
113
|
+
open={showForkModal}
|
|
114
|
+
originalGroup={originalGroupInfo}
|
|
115
|
+
/>
|
|
116
|
+
</>
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
PublishButton.displayName = 'GroupPublishButton';
|
|
121
|
+
|
|
122
|
+
export default PublishButton;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import isEqual from 'fast-deep-equal';
|
|
2
|
+
import { memo, useCallback, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
5
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
6
|
+
|
|
7
|
+
import GroupPublishResultModal from './GroupPublishResultModal';
|
|
8
|
+
import PublishButton from './PublishButton';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Group Publish Button Component
|
|
12
|
+
*
|
|
13
|
+
* Simplified version - backend handles ownership check automatically.
|
|
14
|
+
* The action type (submit vs upload) is determined by backend based on:
|
|
15
|
+
* 1. Whether the identifier exists
|
|
16
|
+
* 2. Whether the current user is the owner
|
|
17
|
+
*/
|
|
18
|
+
const GroupPublishButton = memo(() => {
|
|
19
|
+
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup, isEqual);
|
|
20
|
+
|
|
21
|
+
const [showResultModal, setShowResultModal] = useState(false);
|
|
22
|
+
const [publishedIdentifier, setPublishedIdentifier] = useState<string>();
|
|
23
|
+
|
|
24
|
+
const handlePublishSuccess = useCallback((identifier: string) => {
|
|
25
|
+
setPublishedIdentifier(identifier);
|
|
26
|
+
setShowResultModal(true);
|
|
27
|
+
}, []);
|
|
28
|
+
|
|
29
|
+
// Determine action based on whether we have an existing marketIdentifier
|
|
30
|
+
// Backend will verify ownership and decide to create new or update
|
|
31
|
+
// marketIdentifier is stored in editorData
|
|
32
|
+
const action = currentGroup?.editorData?.marketIdentifier ? 'upload' : 'submit';
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<>
|
|
36
|
+
<PublishButton action={action} onPublishSuccess={handlePublishSuccess} />
|
|
37
|
+
<GroupPublishResultModal
|
|
38
|
+
identifier={publishedIdentifier}
|
|
39
|
+
onCancel={() => setShowResultModal(false)}
|
|
40
|
+
open={showResultModal}
|
|
41
|
+
/>
|
|
42
|
+
</>
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export default GroupPublishButton;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import isEqual from 'fast-deep-equal';
|
|
2
|
+
import { useCallback, useRef, useState } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
|
|
5
|
+
import { message } from '@/components/AntdStaticMethods';
|
|
6
|
+
import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
|
|
7
|
+
import { lambdaClient } from '@/libs/trpc/client';
|
|
8
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
9
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
10
|
+
import { useGlobalStore } from '@/store/global';
|
|
11
|
+
import { globalGeneralSelectors } from '@/store/global/selectors';
|
|
12
|
+
|
|
13
|
+
import type { MarketPublishAction, OriginalGroupInfo } from './types';
|
|
14
|
+
import { generateDefaultChangelog } from './utils';
|
|
15
|
+
|
|
16
|
+
interface UseMarketGroupPublishOptions {
|
|
17
|
+
action: MarketPublishAction;
|
|
18
|
+
onSuccess?: (identifier: string) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface CheckOwnershipResult {
|
|
22
|
+
needsForkConfirm: boolean;
|
|
23
|
+
originalGroup: OriginalGroupInfo | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const useMarketGroupPublish = ({ action, onSuccess }: UseMarketGroupPublishOptions) => {
|
|
27
|
+
const { t } = useTranslation('setting');
|
|
28
|
+
const [isPublishing, setIsPublishing] = useState(false);
|
|
29
|
+
const [isCheckingOwnership, setIsCheckingOwnership] = useState(false);
|
|
30
|
+
const isPublishingRef = useRef(false);
|
|
31
|
+
const { isAuthenticated } = useMarketAuth();
|
|
32
|
+
|
|
33
|
+
// Group data from store
|
|
34
|
+
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup);
|
|
35
|
+
const currentGroupMeta = useAgentGroupStore(agentGroupSelectors.currentGroupMeta, isEqual);
|
|
36
|
+
const currentGroupConfig = useAgentGroupStore(agentGroupSelectors.currentGroupConfig, isEqual);
|
|
37
|
+
const currentGroupAgents = useAgentGroupStore(agentGroupSelectors.currentGroupAgents);
|
|
38
|
+
const updateGroupMeta = useAgentGroupStore((s) => s.updateGroupMeta);
|
|
39
|
+
const language = useGlobalStore(globalGeneralSelectors.currentLanguage);
|
|
40
|
+
|
|
41
|
+
const isSubmit = action === 'submit';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check ownership before publishing
|
|
45
|
+
* Returns whether fork confirmation is needed and original group info
|
|
46
|
+
*/
|
|
47
|
+
const checkOwnership = useCallback(async (): Promise<CheckOwnershipResult> => {
|
|
48
|
+
// marketIdentifier is stored in editorData
|
|
49
|
+
const identifier = currentGroup?.editorData?.marketIdentifier as string | undefined;
|
|
50
|
+
|
|
51
|
+
// No identifier means new group, no need to check
|
|
52
|
+
if (!identifier) {
|
|
53
|
+
return { needsForkConfirm: false, originalGroup: null };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
setIsCheckingOwnership(true);
|
|
58
|
+
const result = await lambdaClient.market.agentGroup.checkOwnership.query({ identifier });
|
|
59
|
+
|
|
60
|
+
// If group doesn't exist or user is owner, no confirmation needed
|
|
61
|
+
if (!result.exists || result.isOwner) {
|
|
62
|
+
return { needsForkConfirm: false, originalGroup: null };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// User is not owner, need fork confirmation
|
|
66
|
+
return {
|
|
67
|
+
needsForkConfirm: true,
|
|
68
|
+
originalGroup: result.originalGroup as OriginalGroupInfo,
|
|
69
|
+
};
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('[useMarketGroupPublish] Failed to check ownership:', error);
|
|
72
|
+
// On error, proceed without confirmation
|
|
73
|
+
return { needsForkConfirm: false, originalGroup: null };
|
|
74
|
+
} finally {
|
|
75
|
+
setIsCheckingOwnership(false);
|
|
76
|
+
}
|
|
77
|
+
}, [currentGroup]);
|
|
78
|
+
|
|
79
|
+
const publish = useCallback(async () => {
|
|
80
|
+
// Prevent duplicate publishing
|
|
81
|
+
if (isPublishingRef.current) {
|
|
82
|
+
return { success: false };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Check authentication
|
|
86
|
+
if (!isAuthenticated) {
|
|
87
|
+
return { success: false };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!currentGroup) {
|
|
91
|
+
message.error({ content: t('marketPublish.modal.messages.noGroup') });
|
|
92
|
+
return { success: false };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const messageKey = isSubmit ? 'submit-group' : 'upload-group-version';
|
|
96
|
+
const loadingMessage = isSubmit
|
|
97
|
+
? t('marketPublish.modal.loading.submitGroup')
|
|
98
|
+
: t('marketPublish.modal.loading.uploadGroup');
|
|
99
|
+
|
|
100
|
+
const changelog = generateDefaultChangelog();
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
isPublishingRef.current = true;
|
|
104
|
+
setIsPublishing(true);
|
|
105
|
+
message.loading({ content: loadingMessage, key: messageKey });
|
|
106
|
+
|
|
107
|
+
// Prepare member agents data
|
|
108
|
+
const memberAgents = currentGroupAgents.map((agent, index) => ({
|
|
109
|
+
// Only include avatar if it's not null/undefined
|
|
110
|
+
...(agent.avatar ? { avatar: agent.avatar } : {}),
|
|
111
|
+
config: {
|
|
112
|
+
// Include agent configuration
|
|
113
|
+
model: agent.model,
|
|
114
|
+
params: agent.params,
|
|
115
|
+
systemRole: agent.systemRole,
|
|
116
|
+
},
|
|
117
|
+
// Market requires at least 1 character for description
|
|
118
|
+
description: agent.description || 'No description provided',
|
|
119
|
+
displayOrder: index,
|
|
120
|
+
identifier: agent.id, // Use local agent ID as identifier
|
|
121
|
+
name: agent.title || 'Untitled Agent',
|
|
122
|
+
role: agent.isSupervisor ? ('supervisor' as const) : ('participant' as const),
|
|
123
|
+
// TODO: Construct proper A2A URL for the agent
|
|
124
|
+
url: `https://api.lobehub.com/a2a/agents/${agent.id}`,
|
|
125
|
+
}));
|
|
126
|
+
|
|
127
|
+
// Use tRPC publishOrCreate
|
|
128
|
+
const result = await lambdaClient.market.agentGroup.publishOrCreate.mutate({
|
|
129
|
+
// Only include avatar if it's not null/undefined
|
|
130
|
+
...(currentGroupMeta.avatar ? { avatar: currentGroupMeta.avatar } : {}),
|
|
131
|
+
// Only include backgroundColor if it's not null/undefined
|
|
132
|
+
...(currentGroup.backgroundColor ? { backgroundColor: currentGroup.backgroundColor } : {}),
|
|
133
|
+
category: 'productivity', // TODO: Allow user to select category
|
|
134
|
+
changelog,
|
|
135
|
+
// Include group-level config (systemPrompt from content, openingMessage, etc.)
|
|
136
|
+
config: {
|
|
137
|
+
// Group systemPrompt is stored in currentGroup.content
|
|
138
|
+
...(currentGroup.content !== undefined &&
|
|
139
|
+
currentGroup.content !== null && {
|
|
140
|
+
systemPrompt: currentGroup.content,
|
|
141
|
+
}),
|
|
142
|
+
...(currentGroupConfig.openingMessage !== undefined && {
|
|
143
|
+
openingMessage: currentGroupConfig.openingMessage,
|
|
144
|
+
}),
|
|
145
|
+
...(currentGroupConfig.openingQuestions !== undefined &&
|
|
146
|
+
currentGroupConfig.openingQuestions.length > 0 && {
|
|
147
|
+
openingQuestions: currentGroupConfig.openingQuestions,
|
|
148
|
+
}),
|
|
149
|
+
...(currentGroupConfig.allowDM !== undefined && { allowDM: currentGroupConfig.allowDM }),
|
|
150
|
+
...(currentGroupConfig.revealDM !== undefined && { revealDM: currentGroupConfig.revealDM }),
|
|
151
|
+
},
|
|
152
|
+
// Market requires at least 1 character for description
|
|
153
|
+
description: currentGroupMeta.description || 'No description provided',
|
|
154
|
+
// marketIdentifier is stored in editorData
|
|
155
|
+
identifier: currentGroup.editorData?.marketIdentifier as string | undefined,
|
|
156
|
+
memberAgents,
|
|
157
|
+
name: currentGroupMeta.title || 'Untitled Group',
|
|
158
|
+
visibility: 'public', // TODO: Allow user to select visibility
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Save marketIdentifier to editorData if new group
|
|
162
|
+
if (result.isNewGroup) {
|
|
163
|
+
await updateGroupMeta({
|
|
164
|
+
editorData: {
|
|
165
|
+
...currentGroup.editorData,
|
|
166
|
+
marketIdentifier: result.identifier,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
message.success({
|
|
172
|
+
content: t('submitAgentModal.success'),
|
|
173
|
+
key: messageKey,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
onSuccess?.(result.identifier);
|
|
177
|
+
return { identifier: result.identifier, success: true };
|
|
178
|
+
} catch (error) {
|
|
179
|
+
const errorMessage =
|
|
180
|
+
error instanceof Error ? error.message : t('unknownError', { ns: 'common' });
|
|
181
|
+
message.error({
|
|
182
|
+
content: t('marketPublish.modal.messages.publishFailed', {
|
|
183
|
+
message: errorMessage,
|
|
184
|
+
}),
|
|
185
|
+
key: messageKey,
|
|
186
|
+
});
|
|
187
|
+
return { success: false };
|
|
188
|
+
} finally {
|
|
189
|
+
isPublishingRef.current = false;
|
|
190
|
+
setIsPublishing(false);
|
|
191
|
+
}
|
|
192
|
+
}, [
|
|
193
|
+
currentGroup,
|
|
194
|
+
currentGroupAgents,
|
|
195
|
+
currentGroupConfig,
|
|
196
|
+
currentGroupMeta,
|
|
197
|
+
isAuthenticated,
|
|
198
|
+
isSubmit,
|
|
199
|
+
language,
|
|
200
|
+
onSuccess,
|
|
201
|
+
t,
|
|
202
|
+
updateGroupMeta,
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
checkOwnership,
|
|
207
|
+
isCheckingOwnership,
|
|
208
|
+
isPublishing,
|
|
209
|
+
publish,
|
|
210
|
+
};
|
|
211
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { customAlphabet } from 'nanoid/non-secure';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a market identifier (8-character lowercase alphanumeric string)
|
|
5
|
+
* Format: [a-z0-9]{8}
|
|
6
|
+
* @returns A unique 8-character market identifier
|
|
7
|
+
*/
|
|
8
|
+
export const generateMarketIdentifier = () => {
|
|
9
|
+
const alphabet = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
10
|
+
const generate = customAlphabet(alphabet, 8);
|
|
11
|
+
return generate();
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generate a default changelog based on current timestamp
|
|
16
|
+
* @returns A timestamp-based changelog string
|
|
17
|
+
*/
|
|
18
|
+
export const generateDefaultChangelog = () => {
|
|
19
|
+
const now = new Date();
|
|
20
|
+
const formattedDate = now.toISOString().split('T')[0];
|
|
21
|
+
return `Release ${formattedDate}`;
|
|
22
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useUnmount } from 'ahooks';
|
|
2
|
+
import { createStoreUpdater } from 'zustand-utils';
|
|
3
|
+
|
|
4
|
+
import { useAgentStore } from '@/store/agent';
|
|
5
|
+
import { builtinAgentSelectors } from '@/store/agent/selectors';
|
|
6
|
+
|
|
7
|
+
const HomeAgentIdSync = () => {
|
|
8
|
+
const useAgentStoreUpdater = createStoreUpdater(useAgentStore);
|
|
9
|
+
|
|
10
|
+
const inboxAgentId = useAgentStore(builtinAgentSelectors.inboxAgentId);
|
|
11
|
+
|
|
12
|
+
// Sync inbox agent id to activeAgentId when on home page
|
|
13
|
+
useAgentStoreUpdater('activeAgentId', inboxAgentId);
|
|
14
|
+
|
|
15
|
+
// Clear activeAgentId when unmounting (leaving home page)
|
|
16
|
+
useUnmount(() => {
|
|
17
|
+
useAgentStore.setState({ activeAgentId: undefined });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default HomeAgentIdSync;
|
|
@@ -6,6 +6,7 @@ import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
|
|
6
6
|
import { useIsDark } from '@/hooks/useIsDark';
|
|
7
7
|
import { useHomeStore } from '@/store/home';
|
|
8
8
|
|
|
9
|
+
import HomeAgentIdSync from './HomeAgentIdSync';
|
|
9
10
|
import RecentHydration from './RecentHydration';
|
|
10
11
|
import Sidebar from './Sidebar';
|
|
11
12
|
import { styles } from './style';
|
|
@@ -56,6 +57,7 @@ const Layout: FC<LayoutProps> = ({ children }) => {
|
|
|
56
57
|
{content}
|
|
57
58
|
</Flexbox>
|
|
58
59
|
|
|
60
|
+
<HomeAgentIdSync />
|
|
59
61
|
<RecentHydration />
|
|
60
62
|
</Flexbox>
|
|
61
63
|
</Activity>
|
|
@@ -168,6 +168,13 @@ export const desktopRoutes: RouteConfig[] = [
|
|
|
168
168
|
),
|
|
169
169
|
path: 'assistant/:slug',
|
|
170
170
|
},
|
|
171
|
+
{
|
|
172
|
+
element: dynamicElement(
|
|
173
|
+
() => import('../(main)/community/(detail)/group_agent'),
|
|
174
|
+
'Desktop > Discover > Detail > Group Agent',
|
|
175
|
+
),
|
|
176
|
+
path: 'group_agent/:slug',
|
|
177
|
+
},
|
|
171
178
|
{
|
|
172
179
|
element: dynamicElement(
|
|
173
180
|
() => import('../(main)/community/(detail)/model'),
|
|
@@ -187,9 +187,13 @@ export default {
|
|
|
187
187
|
'llm.waitingForMoreLinkAriaLabel': 'Open the Provider request form',
|
|
188
188
|
'marketPublish.forkConfirm.by': 'by {{author}}',
|
|
189
189
|
'marketPublish.forkConfirm.confirm': 'Confirm Publish',
|
|
190
|
+
'marketPublish.forkConfirm.confirmGroup': 'Confirm Publish',
|
|
190
191
|
'marketPublish.forkConfirm.description':
|
|
191
192
|
'You are about to publish a derivative version based on an existing agent from the community. Your new agent will be created as a separate entry in the marketplace.',
|
|
193
|
+
'marketPublish.forkConfirm.descriptionGroup':
|
|
194
|
+
'You are about to publish a derivative version based on an existing group from the community. Your new group will be created as a separate entry in the marketplace.',
|
|
192
195
|
'marketPublish.forkConfirm.title': 'Publish Derivative Agent',
|
|
196
|
+
'marketPublish.forkConfirm.titleGroup': 'Publish Derivative Group',
|
|
193
197
|
'marketPublish.modal.changelog.extra':
|
|
194
198
|
'Describe the key changes and improvements in this version',
|
|
195
199
|
'marketPublish.modal.changelog.label': 'Changelog',
|
|
@@ -209,11 +213,14 @@ export default {
|
|
|
209
213
|
'marketPublish.modal.identifier.required': 'Please enter the agent identifier',
|
|
210
214
|
'marketPublish.modal.loading.fetchingRemote': 'Loading remote data...',
|
|
211
215
|
'marketPublish.modal.loading.submit': 'Submitting Agent...',
|
|
216
|
+
'marketPublish.modal.loading.submitGroup': 'Submitting Group...',
|
|
212
217
|
'marketPublish.modal.loading.upload': 'Publishing new version...',
|
|
218
|
+
'marketPublish.modal.loading.uploadGroup': 'Publishing new group version...',
|
|
213
219
|
'marketPublish.modal.messages.createVersionFailed': 'Failed to create version: {{message}}',
|
|
214
220
|
'marketPublish.modal.messages.fetchRemoteFailed': 'Failed to fetch remote agent data',
|
|
215
221
|
'marketPublish.modal.messages.missingIdentifier':
|
|
216
222
|
'This Agent doesn’t have a Community identifier yet.',
|
|
223
|
+
'marketPublish.modal.messages.noGroup': 'No group selected',
|
|
217
224
|
'marketPublish.modal.messages.notAuthenticated': 'Sign in to your Community account first.',
|
|
218
225
|
'marketPublish.modal.messages.publishFailed': 'Publish failed: {{message}}',
|
|
219
226
|
'marketPublish.modal.submitButton': 'Publish',
|
|
@@ -221,12 +228,16 @@ export default {
|
|
|
221
228
|
'marketPublish.modal.title.upload': 'Publish New Version',
|
|
222
229
|
'marketPublish.resultModal.message':
|
|
223
230
|
'Your Agent has been submitted for review. Once approved, it will go live automatically.',
|
|
231
|
+
'marketPublish.resultModal.messageGroup':
|
|
232
|
+
'Your Group has been submitted for review. Once approved, it will go live automatically.',
|
|
224
233
|
'marketPublish.resultModal.title': 'Submission Successful',
|
|
225
234
|
'marketPublish.resultModal.view': 'View in Community',
|
|
226
235
|
'marketPublish.submit.button': 'Share to Community',
|
|
227
236
|
'marketPublish.submit.tooltip': 'Share this Agent to the Community',
|
|
237
|
+
'marketPublish.submitGroup.tooltip': 'Share this Group to the Community',
|
|
228
238
|
'marketPublish.upload.button': 'Publish New Version',
|
|
229
239
|
'marketPublish.upload.tooltip': 'Publish a new version to Agent Community',
|
|
240
|
+
'marketPublish.uploadGroup.tooltip': 'Publish a new version to Group Community',
|
|
230
241
|
'memory.enabled.desc':
|
|
231
242
|
'Allow LobeHub to extract preferences and info from conversations and use them later. You can view, edit, or clear memory anytime.',
|
|
232
243
|
'memory.enabled.title': 'Enable Memory',
|
|
@@ -551,6 +562,7 @@ export default {
|
|
|
551
562
|
'submitAgentModal.placeholder': 'Enter a unique identifier for the agent, e.g. web-development',
|
|
552
563
|
'submitAgentModal.success': 'Agent submitted successfully',
|
|
553
564
|
'submitAgentModal.tooltips': 'Share to Agent Community',
|
|
565
|
+
'submitGroupModal.tooltips': 'Share to Group Community',
|
|
554
566
|
'sync.device.deviceName.hint': 'Add a name for easy identification',
|
|
555
567
|
'sync.device.deviceName.placeholder': 'Enter device name',
|
|
556
568
|
'sync.device.deviceName.title': 'Device Name',
|