mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
✨ feat: support agent group unpublish agents (#11687)
feat: support agent group unpublish agents
This commit is contained in:
@@ -19,7 +19,11 @@ export interface UserDetailContextConfig {
|
||||
isOwner: boolean;
|
||||
mobile?: boolean;
|
||||
onEditProfile?: (onSuccess?: (profile: MarketUserProfile) => void) => void;
|
||||
onStatusChange?: (identifier: string, action: 'publish' | 'unpublish' | 'deprecate') => void;
|
||||
onStatusChange?: (
|
||||
identifier: string,
|
||||
action: 'publish' | 'unpublish' | 'deprecate',
|
||||
type?: 'agent' | 'group',
|
||||
) => void;
|
||||
totalInstalls: number;
|
||||
user: DiscoverUserInfo;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
`,
|
||||
moreButton: css`
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
inset-block-start: 12px;
|
||||
inset-inline-end: 12px;
|
||||
|
||||
@@ -259,14 +260,13 @@ const UserAgentCard = memo<UserAgentCardProps>(
|
||||
width={'100%'}
|
||||
>
|
||||
{isOwner && (
|
||||
<DropdownMenu items={menuItems}>
|
||||
<div
|
||||
className={cx('more-button', styles.moreButton)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Icon icon={MoreVerticalIcon} size={16} style={{ cursor: 'pointer' }} />
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<DropdownMenu items={menuItems as any}>
|
||||
<div className={cx('more-button', styles.moreButton)}>
|
||||
<Icon icon={MoreVerticalIcon} size={16} style={{ cursor: 'pointer' }} />
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
)}
|
||||
<Flexbox
|
||||
align={'flex-start'}
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
'use client';
|
||||
|
||||
import { Avatar, Block, Flexbox, Icon, Tag, Text, Tooltip, TooltipGroup } from '@lobehub/ui';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ClockIcon, DownloadIcon, UsersIcon } from 'lucide-react';
|
||||
import {
|
||||
Tag as AntTag,
|
||||
Avatar,
|
||||
Block,
|
||||
DropdownMenu,
|
||||
Flexbox,
|
||||
Icon,
|
||||
Tag,
|
||||
Text,
|
||||
Tooltip,
|
||||
TooltipGroup,
|
||||
} from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import {
|
||||
AlertTriangle,
|
||||
ClockIcon,
|
||||
DownloadIcon,
|
||||
Eye,
|
||||
EyeOff,
|
||||
MoreVerticalIcon,
|
||||
Pencil,
|
||||
UsersIcon,
|
||||
} from 'lucide-react';
|
||||
import qs from 'query-string';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,9 +30,31 @@ import { Link, useNavigate } from 'react-router-dom';
|
||||
import urlJoin from 'url-join';
|
||||
|
||||
import PublishedTime from '@/components/PublishedTime';
|
||||
import { type DiscoverGroupAgentItem } from '@/types/discover';
|
||||
import { type DiscoverGroupAgentItem, type GroupAgentStatus } from '@/types/discover';
|
||||
import { formatIntergerNumber } from '@/utils/format';
|
||||
|
||||
import { useUserDetailContext } from './DetailProvider';
|
||||
|
||||
const getStatusTagColor = (status?: GroupAgentStatus) => {
|
||||
switch (status) {
|
||||
case 'published': {
|
||||
return 'green';
|
||||
}
|
||||
case 'unpublished': {
|
||||
return 'orange';
|
||||
}
|
||||
case 'deprecated': {
|
||||
return 'red';
|
||||
}
|
||||
case 'archived': {
|
||||
return 'default';
|
||||
}
|
||||
default: {
|
||||
return 'default';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
return {
|
||||
desc: css`
|
||||
@@ -25,6 +67,16 @@ const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
border-block-start: 1px dashed ${cssVar.colorBorder};
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
moreButton: css`
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
inset-block-start: 12px;
|
||||
inset-inline-end: 12px;
|
||||
|
||||
opacity: 0;
|
||||
|
||||
transition: opacity 0.2s;
|
||||
`,
|
||||
secondaryDesc: css`
|
||||
font-size: 12px;
|
||||
color: ${cssVar.colorTextDescription};
|
||||
@@ -47,15 +99,31 @@ const styles = createStaticStyles(({ css, cssVar }) => {
|
||||
color: ${cssVar.colorLink};
|
||||
}
|
||||
`,
|
||||
wrapper: css`
|
||||
&:hover .more-button {
|
||||
opacity: 1;
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
type UserGroupCardProps = DiscoverGroupAgentItem;
|
||||
|
||||
const UserGroupCard = memo<UserGroupCardProps>(
|
||||
({ avatar, title, description, createdAt, category, installCount, identifier, memberCount }) => {
|
||||
const { t } = useTranslation(['discover']);
|
||||
({
|
||||
avatar,
|
||||
title,
|
||||
description,
|
||||
createdAt,
|
||||
category,
|
||||
installCount,
|
||||
identifier,
|
||||
memberCount,
|
||||
status,
|
||||
}) => {
|
||||
const { t } = useTranslation(['discover', 'setting']);
|
||||
const navigate = useNavigate();
|
||||
const { isOwner, onStatusChange } = useUserDetailContext();
|
||||
|
||||
const link = qs.stringifyUrl(
|
||||
{
|
||||
@@ -65,12 +133,55 @@ const UserGroupCard = memo<UserGroupCardProps>(
|
||||
{ skipNull: true },
|
||||
);
|
||||
|
||||
const isPublished = status === 'published';
|
||||
|
||||
const handleCardClick = useCallback(() => {
|
||||
navigate(link);
|
||||
}, [link, navigate]);
|
||||
|
||||
const handleEdit = useCallback(() => {
|
||||
navigate(urlJoin('/group', identifier, 'profile'));
|
||||
}, [identifier, navigate]);
|
||||
|
||||
const handleStatusAction = useCallback(
|
||||
(action: 'publish' | 'unpublish' | 'deprecate') => {
|
||||
onStatusChange?.(identifier, action, 'group');
|
||||
},
|
||||
[identifier, onStatusChange],
|
||||
);
|
||||
|
||||
const menuItems = isOwner
|
||||
? [
|
||||
{
|
||||
icon: <Icon icon={Pencil} />,
|
||||
key: 'edit',
|
||||
label: t('setting:myAgents.actions.edit'),
|
||||
onClick: handleEdit,
|
||||
},
|
||||
{
|
||||
type: 'divider' as const,
|
||||
},
|
||||
{
|
||||
icon: <Icon icon={isPublished ? EyeOff : Eye} />,
|
||||
key: 'togglePublish',
|
||||
label: isPublished
|
||||
? t('setting:myAgents.actions.unpublish')
|
||||
: t('setting:myAgents.actions.publish'),
|
||||
onClick: () => handleStatusAction(isPublished ? 'unpublish' : 'publish'),
|
||||
},
|
||||
{
|
||||
danger: true,
|
||||
icon: <Icon icon={AlertTriangle} />,
|
||||
key: 'deprecate',
|
||||
label: t('setting:myAgents.actions.deprecate'),
|
||||
onClick: () => handleStatusAction('deprecate'),
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
return (
|
||||
<Block
|
||||
className={styles.wrapper}
|
||||
clickable
|
||||
height={'100%'}
|
||||
onClick={handleCardClick}
|
||||
@@ -82,6 +193,15 @@ const UserGroupCard = memo<UserGroupCardProps>(
|
||||
variant={'outlined'}
|
||||
width={'100%'}
|
||||
>
|
||||
{isOwner && (
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<DropdownMenu items={menuItems as any}>
|
||||
<div className={cx('more-button', styles.moreButton)}>
|
||||
<Icon icon={MoreVerticalIcon} size={16} style={{ cursor: 'pointer' }} />
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
)}
|
||||
<Flexbox
|
||||
align={'flex-start'}
|
||||
gap={16}
|
||||
@@ -105,15 +225,22 @@ const UserGroupCard = memo<UserGroupCardProps>(
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{ color: 'inherit', flex: 1, overflow: 'hidden' }}
|
||||
to={link}
|
||||
>
|
||||
<Text as={'h3'} className={styles.title} ellipsis style={{ flex: 1 }}>
|
||||
{title}
|
||||
</Text>
|
||||
</Link>
|
||||
<Flexbox align={'center'} gap={8} horizontal>
|
||||
<Link
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{ color: 'inherit', flex: 1, overflow: 'hidden' }}
|
||||
to={link}
|
||||
>
|
||||
<Text as={'h3'} className={styles.title} ellipsis style={{ flex: 1 }}>
|
||||
{title}
|
||||
</Text>
|
||||
</Link>
|
||||
{isOwner && status && (
|
||||
<AntTag color={getStatusTagColor(status)} style={{ flexShrink: 0, margin: 0 }}>
|
||||
{t(`setting:myAgents.status.${status}`)}
|
||||
</AntTag>
|
||||
)}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
|
||||
@@ -6,8 +6,10 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
|
||||
import { marketApiService } from '@/services/marketApi';
|
||||
import { serverConfigSelectors, useServerConfigStore } from '@/store/serverConfig';
|
||||
|
||||
export type AgentStatusAction = 'publish' | 'unpublish' | 'deprecate';
|
||||
export type EntityType = 'agent' | 'group';
|
||||
|
||||
interface UseUserDetailOptions {
|
||||
onMutate?: () => void;
|
||||
@@ -17,43 +19,67 @@ export const useUserDetail = ({ onMutate }: UseUserDetailOptions = {}) => {
|
||||
const { t } = useTranslation('setting');
|
||||
const { message, modal } = App.useApp();
|
||||
const { session } = useMarketAuth();
|
||||
const enableMarketTrustedClient = useServerConfigStore(
|
||||
serverConfigSelectors.enableMarketTrustedClient,
|
||||
);
|
||||
|
||||
const handleStatusChange = useCallback(
|
||||
async (identifier: string, action: AgentStatusAction) => {
|
||||
if (!session?.accessToken) {
|
||||
async (identifier: string, action: AgentStatusAction, type: EntityType = 'agent') => {
|
||||
if (!enableMarketTrustedClient && !session?.accessToken) {
|
||||
message.error(t('myAgents.errors.notAuthenticated'));
|
||||
return;
|
||||
}
|
||||
|
||||
const messageKey = `agent-status-${action}`;
|
||||
const messageKey = `${type}-status-${action}`;
|
||||
const loadingText = t(`myAgents.actions.${action}Loading` as any);
|
||||
const successText = t(`myAgents.actions.${action}Success` as any);
|
||||
const errorText = t(`myAgents.actions.${action}Error` as any);
|
||||
|
||||
async function executeStatusChange(identifier: string, action: AgentStatusAction) {
|
||||
async function executeStatusChange(
|
||||
identifier: string,
|
||||
action: AgentStatusAction,
|
||||
type: EntityType,
|
||||
) {
|
||||
try {
|
||||
message.loading({ content: loadingText, key: messageKey });
|
||||
marketApiService.setAccessToken(session!.accessToken);
|
||||
|
||||
switch (action) {
|
||||
case 'publish': {
|
||||
await marketApiService.publishAgent(identifier);
|
||||
break;
|
||||
if (type === 'group') {
|
||||
switch (action) {
|
||||
case 'publish': {
|
||||
await marketApiService.publishAgentGroup(identifier);
|
||||
break;
|
||||
}
|
||||
case 'unpublish': {
|
||||
await marketApiService.unpublishAgentGroup(identifier);
|
||||
break;
|
||||
}
|
||||
case 'deprecate': {
|
||||
await marketApiService.deprecateAgentGroup(identifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 'unpublish': {
|
||||
await marketApiService.unpublishAgent(identifier);
|
||||
break;
|
||||
}
|
||||
case 'deprecate': {
|
||||
await marketApiService.deprecateAgent(identifier);
|
||||
break;
|
||||
} else {
|
||||
switch (action) {
|
||||
case 'publish': {
|
||||
await marketApiService.publishAgent(identifier);
|
||||
break;
|
||||
}
|
||||
case 'unpublish': {
|
||||
await marketApiService.unpublishAgent(identifier);
|
||||
break;
|
||||
}
|
||||
case 'deprecate': {
|
||||
await marketApiService.deprecateAgent(identifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message.success({ content: successText, key: messageKey });
|
||||
onMutate?.();
|
||||
} catch (error) {
|
||||
console.error(`[useUserDetail] ${action} agent error:`, error);
|
||||
console.error(`[useUserDetail] ${action} ${type} error:`, error);
|
||||
message.error({
|
||||
content: `${errorText}: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
key: messageKey,
|
||||
@@ -61,7 +87,6 @@ export const useUserDetail = ({ onMutate }: UseUserDetailOptions = {}) => {
|
||||
}
|
||||
}
|
||||
|
||||
// For deprecate action, show confirmation dialog first
|
||||
if (action === 'deprecate') {
|
||||
modal.confirm({
|
||||
cancelText: t('myAgents.actions.cancel'),
|
||||
@@ -69,16 +94,16 @@ export const useUserDetail = ({ onMutate }: UseUserDetailOptions = {}) => {
|
||||
okButtonProps: { danger: true },
|
||||
okText: t('myAgents.actions.confirmDeprecate'),
|
||||
onOk: async () => {
|
||||
await executeStatusChange(identifier, action);
|
||||
await executeStatusChange(identifier, action, type);
|
||||
},
|
||||
title: t('myAgents.actions.deprecateConfirmTitle'),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await executeStatusChange(identifier, action);
|
||||
await executeStatusChange(identifier, action, type);
|
||||
},
|
||||
[session?.accessToken, message, modal, t, onMutate],
|
||||
[enableMarketTrustedClient, session?.accessToken, message, modal, t, onMutate],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -202,6 +202,66 @@ export const agentGroupRouter = router({
|
||||
|
||||
|
||||
/**
|
||||
* Deprecate agent group
|
||||
* POST /market/agent-group/:identifier/deprecate
|
||||
*/
|
||||
deprecateAgentGroup: agentGroupProcedure
|
||||
.input(z.object({ identifier: z.string() }))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
log('deprecateAgentGroup input: %O', input);
|
||||
|
||||
try {
|
||||
const deprecateUrl = `${MARKET_BASE_URL}/api/v1/agent-groups/${input.identifier}/deprecate`;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
|
||||
const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
|
||||
|
||||
if (userInfo) {
|
||||
const trustedClientToken = generateTrustedClientToken(userInfo);
|
||||
if (trustedClientToken) {
|
||||
headers['x-lobe-trust-token'] = trustedClientToken;
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers['x-lobe-trust-token'] && accessToken) {
|
||||
headers['Authorization'] = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
const response = await fetch(deprecateUrl, {
|
||||
headers,
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
log(
|
||||
'Deprecate agent group failed: %s %s - %s',
|
||||
response.status,
|
||||
response.statusText,
|
||||
errorText,
|
||||
);
|
||||
throw new Error(`Failed to deprecate agent group: ${response.statusText}`);
|
||||
}
|
||||
|
||||
log('Deprecate agent group success');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
log('Error deprecating agent group: %O', error);
|
||||
throw new TRPCError({
|
||||
cause: error,
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
message: error instanceof Error ? error.message : 'Failed to deprecate agent group',
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fork an agent group
|
||||
* POST /market/agent-group/:identifier/fork
|
||||
*/
|
||||
@@ -340,7 +400,6 @@ getAgentGroupForkSource: agentGroupProcedure
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get all forks of an agent group
|
||||
* GET /market/agent-group/:identifier/forks
|
||||
@@ -401,6 +460,66 @@ getAgentGroupForks: agentGroupProcedure
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Publish agent group
|
||||
* POST /market/agent-group/:identifier/publish
|
||||
*/
|
||||
publishAgentGroup: agentGroupProcedure
|
||||
.input(z.object({ identifier: z.string() }))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
log('publishAgentGroup input: %O', input);
|
||||
|
||||
try {
|
||||
const publishUrl = `${MARKET_BASE_URL}/api/v1/agent-groups/${input.identifier}/publish`;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
|
||||
const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
|
||||
|
||||
if (userInfo) {
|
||||
const trustedClientToken = generateTrustedClientToken(userInfo);
|
||||
if (trustedClientToken) {
|
||||
headers['x-lobe-trust-token'] = trustedClientToken;
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers['x-lobe-trust-token'] && accessToken) {
|
||||
headers['Authorization'] = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
const response = await fetch(publishUrl, {
|
||||
headers,
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
log(
|
||||
'Publish agent group failed: %s %s - %s',
|
||||
response.status,
|
||||
response.statusText,
|
||||
errorText,
|
||||
);
|
||||
throw new Error(`Failed to publish agent group: ${response.statusText}`);
|
||||
}
|
||||
|
||||
log('Publish agent group success');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
log('Error publishing agent group: %O', error);
|
||||
throw new TRPCError({
|
||||
cause: error,
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
message: error instanceof Error ? error.message : 'Failed to publish agent group',
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Unified publish or create agent group flow
|
||||
* 1. Check if identifier exists and if current user is owner
|
||||
@@ -494,6 +613,65 @@ publishOrCreate: agentGroupProcedure
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
/**
|
||||
* Unpublish agent group
|
||||
* POST /market/agent-group/:identifier/unpublish
|
||||
*/
|
||||
unpublishAgentGroup: agentGroupProcedure
|
||||
.input(z.object({ identifier: z.string() }))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
log('unpublishAgentGroup input: %O', input);
|
||||
|
||||
try {
|
||||
const unpublishUrl = `${MARKET_BASE_URL}/api/v1/agent-groups/${input.identifier}/unpublish`;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
|
||||
const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
|
||||
|
||||
if (userInfo) {
|
||||
const trustedClientToken = generateTrustedClientToken(userInfo);
|
||||
if (trustedClientToken) {
|
||||
headers['x-lobe-trust-token'] = trustedClientToken;
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers['x-lobe-trust-token'] && accessToken) {
|
||||
headers['Authorization'] = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
const response = await fetch(unpublishUrl, {
|
||||
headers,
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
log(
|
||||
'Unpublish agent group failed: %s %s - %s',
|
||||
response.status,
|
||||
response.statusText,
|
||||
errorText,
|
||||
);
|
||||
throw new Error(`Failed to unpublish agent group: ${response.statusText}`);
|
||||
}
|
||||
|
||||
log('Unpublish agent group success');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
log('Error unpublishing agent group: %O', error);
|
||||
throw new TRPCError({
|
||||
cause: error,
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
message: error instanceof Error ? error.message : 'Failed to unpublish agent group',
|
||||
});
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
export type AgentGroupRouter = typeof agentGroupRouter;
|
||||
|
||||
@@ -1761,6 +1761,7 @@ export class DiscoverService {
|
||||
knowledgeCount: agent.knowledgeCount || 0,
|
||||
pluginCount: agent.pluginCount || 0,
|
||||
schemaVersion: 1,
|
||||
status: agent.status,
|
||||
tags: agent.tags || [],
|
||||
title: agent.name || agent.identifier,
|
||||
tokenUsage: agent.tokenUsage || 0,
|
||||
@@ -1780,6 +1781,7 @@ export class DiscoverService {
|
||||
isOfficial: group.isOfficial || false,
|
||||
memberCount: 0, // Will be populated from memberAgents in detail view
|
||||
schemaVersion: 1,
|
||||
status: group.status,
|
||||
tags: group.tags || [],
|
||||
title: group.name || group.identifier,
|
||||
updatedAt: group.updatedAt,
|
||||
@@ -1802,6 +1804,7 @@ export class DiscoverService {
|
||||
knowledgeCount: agent.knowledgeCount || 0,
|
||||
pluginCount: agent.pluginCount || 0,
|
||||
schemaVersion: 1,
|
||||
status: agent.status,
|
||||
tags: agent.tags || [],
|
||||
title: agent.name || agent.identifier,
|
||||
tokenUsage: agent.tokenUsage || 0,
|
||||
@@ -1824,6 +1827,7 @@ export class DiscoverService {
|
||||
isOfficial: group.isOfficial || false,
|
||||
memberCount: 0, // Will be populated from memberAgents in detail view
|
||||
schemaVersion: 1,
|
||||
status: group.status,
|
||||
tags: group.tags || [],
|
||||
title: group.name || group.identifier,
|
||||
updatedAt: group.updatedAt,
|
||||
|
||||
@@ -146,6 +146,20 @@ export class MarketApiService {
|
||||
return lambdaClient.market.agent.getAgentForkSource.query({ identifier });
|
||||
}
|
||||
|
||||
// ==================== Agent Group Status Management ====================
|
||||
|
||||
async publishAgentGroup(identifier: string): Promise<void> {
|
||||
await lambdaClient.market.agentGroup.publishAgentGroup.mutate({ identifier });
|
||||
}
|
||||
|
||||
async unpublishAgentGroup(identifier: string): Promise<void> {
|
||||
await lambdaClient.market.agentGroup.unpublishAgentGroup.mutate({ identifier });
|
||||
}
|
||||
|
||||
async deprecateAgentGroup(identifier: string): Promise<void> {
|
||||
await lambdaClient.market.agentGroup.deprecateAgentGroup.mutate({ identifier });
|
||||
}
|
||||
|
||||
// ==================== Fork Agent Group API ====================
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user