Skip to content

Commit 1a22f53

Browse files
aarora79Ubuntu
andauthored
Complete agent rating system with UI, CLI, and API documentation (#275)
* Add API endpoints for agent rating and user tracking #226 * add rate agent * Add agent rating system with CLI support and API documentation - Add rating API endpoints (POST /api/agents/{path}/rate, GET /api/agents/{path}/rating) - Implement rotating buffer for last 100 ratings - Add CLI commands: agent-rate and agent-rating - Update Pydantic models to support float ratings (num_stars: int -> float) - Fix registry_client to send JSON for all agent endpoints - Fix token file parsing to extract access_token from JSON - Update OpenAPI spec with rating endpoints and schemas - Change num_stars from integer to float in AgentCard and AgentInfo models * Add interactive star rating UI component - Create StarRatingWidget component with dropdown interaction - Implement click-to-rate functionality with 5-star selection - Add hover preview and visual feedback - Support rating submission and updates - Show success/loading states with animations - Integrate with AgentCard to replace static rating display - Auto-close dropdown after successful submission - Handle outside-click to close dropdown - Full keyboard navigation support (planned) - Mobile-responsive design with touch-friendly targets * Fix rating count display to use rating_details.length - Changed initialCount from usersCount to rating_details.length - Added rating_details to Agent interface TypeScript definition - This ensures rating count matches actual number of ratings * Update README with agent rating system in What's New section --------- Co-authored-by: Ubuntu <ubuntu@ip-172-31-27-29.us-east-2.compute.internal>
1 parent 81371b5 commit 1a22f53

File tree

11 files changed

+1805
-136
lines changed

11 files changed

+1805
-136
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ Interactive terminal interface for chatting with AI models and discovering MCP t
129129

130130
## What's New
131131

132+
- **⭐ Agent Rating System** - Rate and review agents with an interactive 5-star rating widget. Users can submit ratings via the UI or CLI, view aggregate ratings with individual rating details, and update their existing ratings. Features include a rotating buffer (max 100 ratings per agent), one rating per user, float average calculations, and full OpenAPI documentation. Enables community-driven agent quality assessment and discovery.
132133
- **🧠 Flexible Embeddings Support** - Choose from three embedding provider options for semantic search: local sentence-transformers, OpenAI, or any LiteLLM-supported provider including Amazon Bedrock Titan, Cohere, and 100+ other models. Switch providers with simple configuration changes. [Embeddings Guide](docs/embeddings.md)
133134
- **☁️ AWS ECS Production Deployment** - Production-ready deployment on Amazon ECS Fargate with multi-AZ architecture, Application Load Balancer with HTTPS, auto-scaling, CloudWatch monitoring, and NAT Gateway high availability. Complete Terraform configuration for deploying the entire stack. [ECS Deployment Guide](terraform/aws-ecs/README.md)
134135
- **Federated Registry** - MCP Gateway registry now supports federation of servers and agents from other registries. [Federation Guide](docs/federation.md)

api/registry_client.py

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,33 @@ class AgentSemanticDiscoveryResponse(BaseModel):
417417
agents: List[SemanticDiscoveredAgent] = Field(..., description="Semantically discovered agents")
418418

419419

420+
class RatingDetail(BaseModel):
421+
"""Individual rating detail."""
422+
423+
user: str = Field(..., description="Username who submitted the rating")
424+
rating: int = Field(..., ge=1, le=5, description="Rating value (1-5 stars)")
425+
426+
427+
class RatingRequest(BaseModel):
428+
"""Rating submission request."""
429+
430+
rating: int = Field(..., ge=1, le=5, description="Rating value (1-5 stars)")
431+
432+
433+
class RatingResponse(BaseModel):
434+
"""Rating submission response."""
435+
436+
message: str = Field(..., description="Success message")
437+
average_rating: float = Field(..., ge=1.0, le=5.0, description="Updated average rating")
438+
439+
440+
class RatingInfoResponse(BaseModel):
441+
"""Rating information response."""
442+
443+
num_stars: float = Field(..., ge=0.0, le=5.0, description="Average rating (0.0 if no ratings)")
444+
rating_details: List[RatingDetail] = Field(..., description="Individual ratings (max 100)")
445+
446+
420447
# Anthropic Registry API Models (v0.1)
421448

422449

@@ -588,9 +615,9 @@ def _make_request(
588615
logger.debug(f"{method} {url}")
589616

590617
# Determine content type based on endpoint
591-
# Agent registration uses JSON, server registration uses form data
592-
if endpoint == "/api/agents/register":
593-
# Send as JSON for agent registration
618+
# Agent endpoints use JSON, server registration uses form data
619+
if endpoint.startswith("/api/agents"):
620+
# Send as JSON for all agent endpoints
594621
response = requests.request(
595622
method=method,
596623
url=url,
@@ -1169,6 +1196,74 @@ def discover_agents_semantic(
11691196
logger.info(f"Discovered {len(result.agents)} agents via semantic search")
11701197
return result
11711198

1199+
1200+
def rate_agent(
1201+
self,
1202+
path: str,
1203+
rating: int
1204+
) -> RatingResponse:
1205+
"""
1206+
Submit a rating for an agent (1-5 stars).
1207+
1208+
Each user can only have one active rating. If user has already rated,
1209+
this updates their existing rating. System maintains a rotating buffer
1210+
of the last 100 ratings.
1211+
1212+
Args:
1213+
path: Agent path (e.g., /code-reviewer)
1214+
rating: Rating value (1-5 stars)
1215+
1216+
Returns:
1217+
Rating response with success message and updated average rating
1218+
1219+
Raises:
1220+
requests.HTTPError: If rating fails (400 for invalid rating, 403 for unauthorized, 404 for not found)
1221+
"""
1222+
logger.info(f"Rating agent '{path}' with {rating} stars")
1223+
1224+
request_data = RatingRequest(rating=rating)
1225+
1226+
response = self._make_request(
1227+
method="POST",
1228+
endpoint=f"/api/agents{path}/rate",
1229+
data=request_data.model_dump()
1230+
)
1231+
1232+
result = RatingResponse(**response.json())
1233+
logger.info(f"Agent '{path}' rated successfully. New average: {result.average_rating:.2f}")
1234+
return result
1235+
1236+
1237+
def get_agent_rating(
1238+
self,
1239+
path: str
1240+
) -> RatingInfoResponse:
1241+
"""
1242+
Get rating information for an agent.
1243+
1244+
Returns average rating and up to 100 most recent individual ratings
1245+
(maintained as rotating buffer).
1246+
1247+
Args:
1248+
path: Agent path (e.g., /code-reviewer)
1249+
1250+
Returns:
1251+
Rating information with average and individual ratings
1252+
1253+
Raises:
1254+
requests.HTTPError: If retrieval fails (403 for unauthorized, 404 for not found)
1255+
"""
1256+
logger.info(f"Getting ratings for agent: {path}")
1257+
1258+
response = self._make_request(
1259+
method="GET",
1260+
endpoint=f"/api/agents{path}/rating"
1261+
)
1262+
1263+
result = RatingInfoResponse(**response.json())
1264+
logger.info(f"Retrieved ratings for '{path}': {result.num_stars:.2f} stars ({len(result.rating_details)} ratings)")
1265+
return result
1266+
11721267
# Anthropic Registry API Methods (v0.1)
11731268

11741269
def anthropic_list_servers(

api/registry_management.py

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
# Delete agent
4545
uv run python registry_management.py agent-delete --path /code-reviewer
4646
47+
# Rate an agent (1-5 stars)
48+
uv run python registry_management.py agent-rate --path /code-reviewer --rating 5
49+
50+
# Get agent rating information
51+
uv run python registry_management.py agent-rating --path /code-reviewer
52+
4753
# Discover agents by skills
4854
uv run python registry_management.py agent-discover --skills code_analysis,bug_detection
4955
@@ -103,6 +109,8 @@
103109
AgentToggleResponse,
104110
AgentDiscoveryResponse,
105111
AgentSemanticDiscoveryResponse,
112+
RatingResponse,
113+
RatingInfoResponse,
106114
AnthropicServerList,
107115
AnthropicServerResponse,
108116
)
@@ -277,7 +285,18 @@ def _create_client(
277285
raise FileNotFoundError(f"Token file not found: {args.token_file}")
278286

279287
logger.debug(f"Loading token from file: {args.token_file}")
280-
token = token_path.read_text().strip()
288+
289+
# Try to parse as JSON first (token files from generate-agent-token.sh)
290+
try:
291+
with open(token_path, 'r') as f:
292+
token_data = json.load(f)
293+
# Extract access_token from JSON structure
294+
token = token_data.get('access_token')
295+
if not token:
296+
raise RuntimeError(f"No 'access_token' field found in token file: {args.token_file}")
297+
except json.JSONDecodeError:
298+
# Fall back to plain text token file
299+
token = token_path.read_text().strip()
281300

282301
if not token:
283302
raise RuntimeError(f"Empty token in file: {args.token_file}")
@@ -1030,6 +1049,67 @@ def cmd_agent_search(args: argparse.Namespace) -> int:
10301049
return 1
10311050

10321051

1052+
def cmd_agent_rate(args: argparse.Namespace) -> int:
1053+
"""
1054+
Rate an agent (1-5 stars).
1055+
1056+
Args:
1057+
args: Command arguments with path and rating
1058+
1059+
Returns:
1060+
Exit code (0 for success, 1 for failure)
1061+
"""
1062+
try:
1063+
client = _create_client(args)
1064+
response: RatingResponse = client.rate_agent(
1065+
path=args.path,
1066+
rating=args.rating
1067+
)
1068+
1069+
logger.info(f"✓ {response.message}")
1070+
logger.info(f"Average rating: {response.average_rating:.2f} stars")
1071+
1072+
return 0
1073+
1074+
except Exception as e:
1075+
logger.error(f"Failed to rate agent: {e}")
1076+
return 1
1077+
1078+
1079+
def cmd_agent_rating(args: argparse.Namespace) -> int:
1080+
"""
1081+
Get rating information for an agent.
1082+
1083+
Args:
1084+
args: Command arguments with path
1085+
1086+
Returns:
1087+
Exit code (0 for success, 1 for failure)
1088+
"""
1089+
try:
1090+
client = _create_client(args)
1091+
response: RatingInfoResponse = client.get_agent_rating(path=args.path)
1092+
1093+
logger.info(f"\nRating for agent '{args.path}':")
1094+
logger.info(f" Average: {response.num_stars:.2f} stars")
1095+
logger.info(f" Total ratings: {len(response.rating_details)}")
1096+
1097+
if response.rating_details:
1098+
logger.info("\nIndividual ratings (most recent):")
1099+
# Show first 10 ratings
1100+
for detail in response.rating_details[:10]:
1101+
logger.info(f" {detail.user}: {detail.rating} stars")
1102+
1103+
if len(response.rating_details) > 10:
1104+
logger.info(f" ... and {len(response.rating_details) - 10} more")
1105+
1106+
return 0
1107+
1108+
except Exception as e:
1109+
logger.error(f"Failed to get ratings: {e}")
1110+
return 1
1111+
1112+
10331113
def cmd_anthropic_list_servers(args: argparse.Namespace) -> int:
10341114
"""
10351115
List all servers using Anthropic Registry API v0.1.
@@ -1480,6 +1560,29 @@ def main() -> int:
14801560
help="Maximum number of results (default: 10)"
14811561
)
14821562

1563+
# Agent rate command
1564+
agent_rate_parser = subparsers.add_parser("agent-rate", help="Rate an agent (1-5 stars)")
1565+
agent_rate_parser.add_argument(
1566+
"--path",
1567+
required=True,
1568+
help="Agent path (e.g., /code-reviewer)"
1569+
)
1570+
agent_rate_parser.add_argument(
1571+
"--rating",
1572+
required=True,
1573+
type=int,
1574+
choices=[1, 2, 3, 4, 5],
1575+
help="Rating value (1-5 stars)"
1576+
)
1577+
1578+
# Agent rating command
1579+
agent_rating_parser = subparsers.add_parser("agent-rating", help="Get rating information for an agent")
1580+
agent_rating_parser.add_argument(
1581+
"--path",
1582+
required=True,
1583+
help="Agent path (e.g., /code-reviewer)"
1584+
)
1585+
14831586
# Anthropic Registry API Commands
14841587

14851588
# Anthropic list servers command
@@ -1565,6 +1668,8 @@ def main() -> int:
15651668
"agent-toggle": cmd_agent_toggle,
15661669
"agent-discover": cmd_agent_discover,
15671670
"agent-search": cmd_agent_search,
1671+
"agent-rate": cmd_agent_rate,
1672+
"agent-rating": cmd_agent_rating,
15681673
"anthropic-list": cmd_anthropic_list_servers,
15691674
"anthropic-versions": cmd_anthropic_list_versions,
15701675
"anthropic-get": cmd_anthropic_get_server

0 commit comments

Comments
 (0)