Skip to content
Merged
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
81 changes: 52 additions & 29 deletions app/api/agents/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,28 @@ import { kv } from "@vercel/kv";
import { listAgentsFiltered, createAgent, Agent } from "@bitte-ai/data";
import { stringifyJsonWithBigint } from "@/lib/utils";

type AgentWithPings = Agent & { pings: number };

const getTotalPingsByAgentIds = async (
agentIds: string[]
): Promise<Record<string, number | null>> => {
if (agentIds.length === 0) {
return {};
}

const pipeline = kv.pipeline();
agentIds.forEach((id) => {
pipeline.get<number>(`smart-action:v1.0:agent:${id}:pings`);
});

const values = await pipeline.exec<number[]>();

return agentIds.reduce((acc, id, index) => {
acc[id] = values[index];
return acc;
}, {} as Record<string, number | null>);
};

export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
Expand All @@ -17,33 +39,54 @@ export async function GET(request: NextRequest) {
const accountId = searchParams.get("accountId") || undefined;
const searchTerm = searchParams.get("searchTerm") || undefined;

// When verifiedOnly is false, we need to fetch all agents first to sort by pings properly
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we sort verified by pings as well?

// before applying pagination. Otherwise, we paginate before sorting which gives wrong results.
const shouldSortByPings = verifiedOnly === false;

const agents = await listAgentsFiltered({
searchTerm,
verified: verifiedOnly,
chainIds,
offset,
limit,
offset: shouldSortByPings ? 0 : offset,
limit: shouldSortByPings ? 20000 : limit, // Get all agents when we need to sort by pings
categories: category ? [category] : undefined,
accountId,
});

if (agents.length === 0) {
return NextResponse.json(agents, { status: 200 });
const response = NextResponse.json(agents, { status: 200 });
response.headers.set('Cache-Control', 'public, max-age=60, s-maxage=120');
return response;
}

const agentIds = agents.map((agent) => agent.id);
const agentIds = agents.map((agent: Agent) => agent.id);
const pingsByAgent = await getTotalPingsByAgentIds(agentIds);

const agentsWithPings = agents.map((agent) => ({
const agentsWithPings: AgentWithPings[] = agents.map((agent: Agent) => ({
...agent,
pings: pingsByAgent[agent.id] || 0,
}));

const sortedAgents = agentsWithPings.sort(
(a, b) => (b.pings as number) - (a.pings as number)
);
let finalAgents = agentsWithPings;

// Sort by pings when verifiedOnly is false
if (shouldSortByPings) {
const sortedAgents = agentsWithPings.sort(
(a: AgentWithPings, b: AgentWithPings) => b.pings - a.pings
);

return NextResponse.json(JSON.parse(stringifyJsonWithBigint(sortedAgents)));
// Apply pagination after sorting
finalAgents = sortedAgents.slice(offset, offset + limit);
}

const result = JSON.parse(stringifyJsonWithBigint(finalAgents));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stringify, then parse?


const response = NextResponse.json(result);
// Add cache headers for browser/CDN caching
response.headers.set('Cache-Control', 'public, max-age=60, s-maxage=120');
response.headers.set('Vary', 'Accept-Encoding');

return response;
} catch (error) {
console.error("Error fetching agents:", error);
return NextResponse.json(
Expand Down Expand Up @@ -97,23 +140,3 @@ export async function POST(request: NextRequest) {
);
}
}

const getTotalPingsByAgentIds = async (
agentIds: string[]
): Promise<Record<string, number | null>> => {
if (agentIds.length === 0) {
return {};
}

const pipeline = kv.pipeline();
agentIds.forEach((id) => {
pipeline.get<number>(`smart-action:v1.0:agent:${id}:pings`);
});

const values = await pipeline.exec<number[]>();

return agentIds.reduce((acc, id, index) => {
acc[id] = values[index];
return acc;
}, {} as Record<string, number | null>);
};