diff --git a/backend/apps/agent_app.py b/backend/apps/agent_app.py
index 89390b2997..7625aa46fb 100644
--- a/backend/apps/agent_app.py
+++ b/backend/apps/agent_app.py
@@ -837,6 +837,9 @@ async def list_agent_page_api(
search_tag_predicates: Optional[str] = Query(None, description="Text-search tag predicates as JSON"),
page: int = Query(1, ge=1, description="Page number starting from 1"),
page_size: int = Query(20, ge=1, le=100, description="Items per page"),
+ include_repository_info: bool = Query(
+ False, description="Include repository listings for agents on this page"
+ ),
authorization: Optional[str] = Header(None),
request: Request = None,
):
@@ -852,11 +855,13 @@ async def list_agent_page_api(
kwargs = {
"tenant_id": resolved_tenant_id,
"user_id": user_id,
+ "caller_tenant_id": auth_tenant_id,
"permission": permission,
"tag": tag,
"search": search,
"page": page,
"page_size": page_size,
+ "include_repository_info": include_repository_info,
}
if created_by:
kwargs["created_by"] = created_by
diff --git a/backend/database/agent_repository_db.py b/backend/database/agent_repository_db.py
index 053a11407d..e8da664569 100644
--- a/backend/database/agent_repository_db.py
+++ b/backend/database/agent_repository_db.py
@@ -354,6 +354,7 @@ def list_agent_repository_by_agent_ids(
*,
statuses: Collection[str],
publisher_tenant_id: str,
+ publisher_user_id: Optional[str] = None,
) -> List[dict]:
"""List repository rows for the given agents, scoped to publisher tenant and statuses."""
if not agent_ids:
@@ -361,7 +362,7 @@ def list_agent_repository_by_agent_ids(
status_list = list(statuses)
with get_db_session() as session:
- rows = (
+ query = (
session.query(
AgentRepository.agent_repository_id,
AgentRepository.agent_id,
@@ -377,7 +378,11 @@ def list_agent_repository_by_agent_ids(
AgentRepository.agent_id.in_(agent_ids),
AgentRepository.status.in_(status_list),
)
- .order_by(
+ )
+ if publisher_user_id is not None:
+ query = query.filter(AgentRepository.publisher_user_id == publisher_user_id)
+ rows = (
+ query.order_by(
AgentRepository.agent_id,
AgentRepository.create_time.desc(),
)
diff --git a/backend/management/services/agent/management.py b/backend/management/services/agent/management.py
index 2e12564abd..8301042879 100644
--- a/backend/management/services/agent/management.py
+++ b/backend/management/services/agent/management.py
@@ -14,6 +14,7 @@
from agents.create_agent_info import create_tool_config_list
from utils.agent_transfer_utils import portable_tool_params, validate_import_tool_params
from services.agent_version_service import publish_version_impl
+from consts.agent_repository import STATUS_PENDING_REVIEW, STATUS_REJECTED, STATUS_SHARED
from consts.const import TOOL_TYPE_MAPPING, \
MODEL_CONFIG_MAPPING, CAN_EDIT_ALL_USER_ROLES, PERMISSION_PRIVATE
from consts.exceptions import (
@@ -67,6 +68,7 @@
)
from database import skill_db
from management.services.skill.service import SkillService
+from database.agent_repository_db import list_agent_repository_by_agent_ids
from database.agent_version_db import batch_search_version_names, query_version_list
from database.group_db import query_group_ids_by_user
from database.user_tenant_db import get_user_tenant_by_user_id
@@ -922,6 +924,7 @@ async def list_all_agent_info_impl(
async def list_agent_page_impl(
tenant_id: str,
user_id: str,
+ caller_tenant_id: Optional[str] = None,
permission: Optional[str] = None,
tag: Optional[str] = None,
search: Optional[str] = None,
@@ -932,6 +935,7 @@ async def list_agent_page_impl(
created_by_not: Optional[str] = None,
tag_predicates: Optional[list] = None,
search_tag_predicates: Optional[list] = None,
+ include_repository_info: bool = False,
) -> Dict[str, Any]:
"""List visible agents with server-side filters and pagination."""
if created_by and created_by_not:
@@ -1127,6 +1131,72 @@ async def list_agent_page_impl(
)
agent["version_label"] = version.get("version_name")
agent["version_create_time"] = version.get("create_time")
+ if include_repository_info:
+ for scope_tenant_id in tenant_ids:
+ scoped_agents = [
+ agent for scope, agent in paged_scoped_agents
+ if scope == scope_tenant_id
+ ]
+ if not scoped_agents:
+ continue
+ scoped_agent_ids = [int(agent["agent_id"]) for agent in scoped_agents]
+ shared_records = list_agent_repository_by_agent_ids(
+ scoped_agent_ids,
+ statuses=(STATUS_SHARED,),
+ publisher_tenant_id=scope_tenant_id,
+ )
+ publisher_records = []
+ if scope_tenant_id == caller_tenant_id and user_role == "ADMIN":
+ publisher_records = list_agent_repository_by_agent_ids(
+ scoped_agent_ids,
+ statuses=(STATUS_PENDING_REVIEW, STATUS_REJECTED, STATUS_SHARED),
+ publisher_tenant_id=scope_tenant_id,
+ )
+ elif scope_tenant_id == caller_tenant_id and user_role == "DEV":
+ publisher_records = list_agent_repository_by_agent_ids(
+ scoped_agent_ids,
+ statuses=(STATUS_PENDING_REVIEW, STATUS_REJECTED, STATUS_SHARED),
+ publisher_tenant_id=scope_tenant_id,
+ publisher_user_id=user_id,
+ )
+ records_by_id = {
+ int(record["agent_repository_id"]): (record, False)
+ for record in shared_records
+ if record["status"] == STATUS_SHARED
+ }
+ records_by_id.update({
+ int(record["agent_repository_id"]): (record, True)
+ for record in publisher_records
+ })
+ repository_by_agent_id: dict[int, list[dict]] = {}
+ for record, is_publisher in records_by_id.values():
+ created_at = record.get("create_time")
+ repository_by_agent_id.setdefault(int(record["agent_id"]), []).append(
+ {
+ "agent_repository_id": record["agent_repository_id"],
+ "status": record["status"],
+ "version_no": record["version_no"],
+ "version_label": record.get("version_name"),
+ "create_time": (
+ created_at.isoformat()
+ if hasattr(created_at, "isoformat")
+ else created_at
+ ),
+ "content": record.get("content") if is_publisher else None,
+ }
+ )
+ for records in repository_by_agent_id.values():
+ records.sort(
+ key=lambda item: (
+ str(item["create_time"] or ""),
+ int(item["agent_repository_id"]),
+ ),
+ reverse=True,
+ )
+ for agent in scoped_agents:
+ agent["repository_info"] = repository_by_agent_id.get(
+ int(agent["agent_id"]), []
+ )
paged_agents = [agent for _, agent in paged_scoped_agents]
return {
"items": paged_agents,
diff --git a/frontend/app/[locale]/agent-space/components/MyAgentCard.tsx b/frontend/app/[locale]/agent-space/components/MyAgentCard.tsx
index c997191b2b..7d8b8d64fc 100644
--- a/frontend/app/[locale]/agent-space/components/MyAgentCard.tsx
+++ b/frontend/app/[locale]/agent-space/components/MyAgentCard.tsx
@@ -1,9 +1,7 @@
"use client";
-import { Button, Dropdown, Spin, Tooltip } from "antd";
+import { Button, Dropdown, Tooltip } from "antd";
import type { MenuProps } from "antd";
-import { useState } from "react";
-import { useAgentRepositoryListings } from "@/hooks/agentRepository/useAgentRepositoryListings";
import {
ClipboardCheck,
Clock,
@@ -21,7 +19,7 @@ import { getUnavailableReasonLabels } from "@/lib/agentLabelMapper";
import {
formatMineDate,
getMineCardMenuActions,
- toMineRepositoryInfo,
+ getMineCardRepositoryStatusBadge,
type MineCardMenuAction,
} from "@/lib/agentRepositoryMine";
import type { MyEditableAgentItem } from "@/types/agentRepository";
@@ -69,16 +67,6 @@ export function MyAgentCard({
isDeleting = false,
}: MyAgentCardProps) {
const { t } = useTranslation("common");
- const [menuOpen, setMenuOpen] = useState(false);
- const {
- data: listingData,
- isLoading: isListingLoading,
- isError: isListingError,
- refetch,
- } = useAgentRepositoryListings(
- { agent_id: agent.agent_id, page: 1, page_size: 100 },
- menuOpen || guideMenuOpen === true
- );
const title = agent.name?.trim() || t("agentRepository.card.untitled");
const description =
@@ -88,8 +76,6 @@ export function MyAgentCard({
agent.unavailable_reasons ?? [],
t
);
- const repositoryInfo = toMineRepositoryInfo(listingData?.items ?? []);
- const agentWithRepository = { ...agent, repository_info: repositoryInfo };
const { canOpen: published } = getAgentUsageGuideAccess({
currentVersionNo: agent.current_version_no,
permission: agent.permission,
@@ -99,9 +85,10 @@ export function MyAgentCard({
const canEdit = agent.permission !== "READ_ONLY";
const canView = (agent.current_version_no ?? 0) > 0;
const canEvaluate = canView;
- const menuActions = listingData
- ? getMineCardMenuActions(agentWithRepository)
- : [];
+ const menuActions = getMineCardMenuActions(agent);
+ const repositoryBadge = getMineCardRepositoryStatusBadge(
+ agent.repository_info
+ );
const menuItems: MenuProps["items"] = menuActions.map((action) => {
const icon =
@@ -122,29 +109,13 @@ export function MyAgentCard({
return;
}
onViewReview(
- agentWithRepository,
+ agent,
action === "reviewUpdate" ? "reviewUpdate" : "review"
);
},
};
});
- if (isListingLoading) {
- menuItems.unshift({
- key: "loading",
- label: