Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added backend/app/agents.db
Binary file not shown.
46 changes: 46 additions & 0 deletions backend/app/api/trending.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# New router: returns trending agents based on installs (tie-break by rating)
from fastapi import APIRouter, Query
from typing import List
from pathlib import Path
import json

from app.models.schemas import AgentSummary

router = APIRouter()


@router.get("/agents/trending", response_model=List[AgentSummary])
def get_trending(n: int = Query(10, ge=1, le=50)):
#Returns top-N trending agents sorted by installs (rating is the tie breaker)

#Reads agent manifests from the local agents/manifests directory
manifests_dir = Path(__file__).resolve().parents[3] / "agents" / "manifests"
agents = []

if not manifests_dir.exists():
return []

for p in sorted(manifests_dir.glob("*.json")):
try:
data = json.loads(p.read_text())
except Exception:
continue

agent = {
"id": data.get("id") or (data.get("name", "").lower().replace(" ", "_")),
"name": data.get("name", "Unnamed Agent"),
"description": data.get("description", ""),
"category": data.get("category", "uncategorized"),
"rating": float(data.get("rating") or 0.0),
"installs": int(data.get("installs") or data.get("downloads") or 0),
"downloads": int(data.get("downloads") or 0),
"tags": data.get("tags") or [],
"tools_required": data.get("tools_required") or [],
}
agents.append(agent)

# sort by installs desc, then rating desc
agents_sorted = sorted(agents, key=lambda a: (-a.get("installs", 0), -a.get("rating", 0.0)))

top = agents_sorted[:n]
return [AgentSummary(**a) for a in top]
3 changes: 3 additions & 0 deletions backend/app/db/agents_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This file was removed in favor of reading agent manifests directly from agents/manifests.
# The previous implementation used a lightweight SQLite DB. If you need to reintroduce
# a DB-backed layer, implement the data access functions here and update the routers accordingly.
1 change: 1 addition & 0 deletions backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
app.include_router(tools.router, prefix="/tools", tags=["tools"])
app.include_router(runs.router, prefix="/agents", tags=["runs"])
app.include_router(ratings.router, prefix="/agents", tags=["ratings"])
# trending endpoint moved into agents router


@app.get("/")
Expand Down
3 changes: 2 additions & 1 deletion backend/app/models/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class AgentSummary(BaseModel):
description: str
category: str
rating: float = 0.0
installs: int = 0
downloads: int = 0
tags: list[str] = Field(default_factory=list)
tools_required: list[str] = Field(default_factory=list)
Expand All @@ -23,8 +24,8 @@ class AgentDetail(AgentSummary):
creator: str = "Unknown"
version: str = "1.0.0"
status: str = "draft"
installs: int = 0
runs: int = 0
installs: int = 0
permissions_required: list[str] = Field(default_factory=list)
inputs: dict = Field(default_factory=dict)
outputs: dict = Field(default_factory=dict)
Expand Down
34 changes: 33 additions & 1 deletion backend/app/routers/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import sys
from pathlib import Path

from fastapi import APIRouter, HTTPException
from fastapi import APIRouter, HTTPException, Query
from typing import List
import json

# Add agents package to path for registry access
REPO_ROOT = Path(__file__).parent.parent.parent.parent
Expand Down Expand Up @@ -37,6 +39,35 @@ def list_agents():
for a in agents
]

@router.get("/trending", response_model=List[AgentSummary])
def trending(n: int = Query(10, ge=1, le=50)):
"""Return top-N trending agents by reading manifests from agents/manifests (installs desc, rating desc)."""
manifests_dir = Path(__file__).resolve().parents[3] / "agents" / "manifests"
agents = []

if manifests_dir.exists():
for p in sorted(manifests_dir.glob("*.json")):
try:
data = json.loads(p.read_text())
except Exception:
continue

agent = {
"id": data.get("id") or (data.get("name", "").lower().replace(" ", "_")),
"name": data.get("name", "Unnamed Agent"),
"description": data.get("description", ""),
"category": data.get("category", "uncategorized"),
"rating": float(data.get("rating") or 0.0),
"installs": int(data.get("installs") or data.get("downloads") or 0),
"downloads": int(data.get("downloads") or 0),
"tags": data.get("tags") or [],
"tools_required": data.get("tools_required") or [],
}
agents.append(agent)

agents_sorted = sorted(agents, key=lambda a: (-a.get("installs", 0), -a.get("rating", 0.0)))
return [AgentSummary(**a) for a in agents_sorted[:n]]


@router.get("/{agent_id}", response_model=AgentDetail)
def get_agent(agent_id: str):
Expand All @@ -49,3 +80,4 @@ def get_agent(agent_id: str):
if not agent:
raise HTTPException(status_code=404, detail=f"Agent '{agent_id}' not found")
return AgentDetail(**agent)

Loading