From 626d4ba7b2d0e742f3479747253cc8ec2ae462b6 Mon Sep 17 00:00:00 2001 From: Till <till.friesewinkel@googlemail.com> Date: Fri, 14 Mar 2025 15:29:03 +0000 Subject: [PATCH 1/2] Move to SQL database --- .prettierrc | 3 ++ app/api/agents/route.ts | 18 ++++----- lib/firestore.ts | 85 ++++++++++++++++++++++++----------------- package.json | 1 + pnpm-lock.yaml | 33 +++++++++++++++- 5 files changed, 92 insertions(+), 48 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..1ca87ab --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "singleQuote": false +} diff --git a/app/api/agents/route.ts b/app/api/agents/route.ts index e1a6acb..ec879be 100644 --- a/app/api/agents/route.ts +++ b/app/api/agents/route.ts @@ -1,8 +1,7 @@ -import { Agent } from "@/lib/types"; import { NextRequest, NextResponse } from "next/server"; -import { write, queryAgents } from "@/lib/firestore"; -import { COLLECTIONS } from "@/lib/constants"; +import { queryAgents } from "@/lib/firestore"; import { kv } from "@vercel/kv"; +import { listAiAgents, createAiAgent, ai_agent } from "@bitte-ai/data"; export async function GET(request: NextRequest) { try { @@ -13,13 +12,16 @@ export async function GET(request: NextRequest) { const verifiedOnly = searchParams.get("verifiedOnly") !== "false"; const category = searchParams.get("category") || undefined; - const agents = await queryAgents<Agent>({ + // TODO: remove firestore after migration + const firestoreAgents = await queryAgents({ verified: verifiedOnly, chainIds, offset, limit, category: category === "" ? undefined : category, }); + const sqlAgents = await listAiAgents(); + const agents = [...firestoreAgents, ...sqlAgents]; const agentIds = agents.map((agent) => agent.id); const pingsByAgent = await getTotalPingsByAgentIds(agentIds); @@ -47,7 +49,7 @@ export async function POST(request: NextRequest) { try { const body = await request.json(); - const newAgent: Agent = { + const newAgent: ai_agent = { ...body, verified: false, id: crypto.randomUUID(), @@ -73,11 +75,7 @@ export async function POST(request: NextRequest) { ); } - const result = await write(COLLECTIONS.AGENTS, newAgent.id, newAgent); - - if (!result.success) { - throw result.error; - } + await createAiAgent(newAgent); return NextResponse.json(newAgent, { status: 201 }); } catch (error) { diff --git a/lib/firestore.ts b/lib/firestore.ts index a90b337..e0a9316 100644 --- a/lib/firestore.ts +++ b/lib/firestore.ts @@ -4,7 +4,7 @@ import { WithFieldValue, } from "@google-cloud/firestore"; import { COLLECTIONS } from "./constants"; -import { Tool } from "./types"; +import { Agent, Tool } from "./types"; export type FirestoreOperationResult = { success: boolean; @@ -135,26 +135,32 @@ export const catchDocumentNotFound = (err: Error): null => { throw err; }; -export const queryAgents = async <T>(options: { - verified?: boolean; - withTools?: boolean; - chainIds?: string[]; - offset?: number; - limit?: number; - category?: string | null; -} = {}): Promise<T[]> => { +export const queryAgents = async ( + options: { + verified?: boolean; + withTools?: boolean; + chainIds?: string[]; + offset?: number; + limit?: number; + category?: string | null; + } = {} +): Promise<Agent[]> => { let query: FirebaseFirestore.Query = db.collection(COLLECTIONS.AGENTS); - + if (options.verified) { - query = query.where('verified', '==', true); + query = query.where("verified", "==", true); } if (options.chainIds?.length) { - query = query.where('chainIds', 'array-contains-any', options.chainIds.map(id => parseInt(id))); + query = query.where( + "chainIds", + "array-contains-any", + options.chainIds.map((id) => parseInt(id)) + ); } if (options.category) { - query = query.where('category', '==', options.category); + query = query.where("category", "==", options.category); } if (options.limit) { @@ -166,33 +172,36 @@ export const queryAgents = async <T>(options: { } const snapshot = await query.get(); - const agents = snapshot.docs.map(doc => doc.data()); - + const agents = snapshot.docs.map((doc) => doc.data()); + if (!options.withTools) { - return agents.map(agent => { + return agents.map((agent) => { const { ...rest } = agent; - return rest as T; + return rest as Agent; }); } - - return agents as T[]; + + return agents as Agent[]; }; -export const queryTools = async <T>(options: { - verified?: boolean; - functionName?: string; - offset?: number; - chainId?: string; -} = {}): Promise<T[]> => { - let query: FirebaseFirestore.Query = db.collection(COLLECTIONS.AGENTS) - .select('tools', 'image', 'chainIds'); - +export const queryTools = async <T>( + options: { + verified?: boolean; + functionName?: string; + offset?: number; + chainId?: string; + } = {} +): Promise<T[]> => { + let query: FirebaseFirestore.Query = db + .collection(COLLECTIONS.AGENTS) + .select("tools", "image", "chainIds"); + if (options.verified) { - query = query.where('verified', '==', true); + query = query.where("verified", "==", true); } if (options.chainId) { - query = query.where('chainIds', 'array-contains', options.chainId); + query = query.where("chainIds", "array-contains", options.chainId); } const limit = 100; @@ -200,31 +209,35 @@ export const queryTools = async <T>(options: { const snapshot = await query.get(); const tools: Tool[] = []; - + for (const doc of snapshot.docs) { const agent = doc.data(); if (!agent.tools?.length) continue; const baseToolData = { image: agent.image, - chainIds: agent.chainIds || [] + chainIds: agent.chainIds || [], }; for (const tool of agent.tools) { - if (options.functionName && - !tool.function.name.toLowerCase().includes(options.functionName.toLowerCase())) { + if ( + options.functionName && + !tool.function.name + .toLowerCase() + .includes(options.functionName.toLowerCase()) + ) { continue; } tools.push({ ...tool, - ...baseToolData + ...baseToolData, }); } } const uniqueTools = Array.from( - new Map(tools.map(tool => [tool.function.name, tool])).values() + new Map(tools.map((tool) => [tool.function.name, tool])).values() ); if (options.offset) { diff --git a/package.json b/package.json index 87f2ce5..58d6da5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@ai-sdk/openai": "^1.1.11", + "@bitte-ai/data": "0.1.0-fix-cicd2-460c6c4", "@google-cloud/firestore": "^7.11.0", "@jest/globals": "^29.7.0", "@radix-ui/react-dialog": "^1.1.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57bc750..650dc91 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@ai-sdk/openai': specifier: ^1.1.11 version: 1.1.11(zod@3.24.2) + '@bitte-ai/data': + specifier: 0.1.0-fix-cicd2-460c6c4 + version: 0.1.0-fix-cicd2-460c6c4(typescript@5.7.3) '@google-cloud/firestore': specifier: ^7.11.0 version: 7.11.0 @@ -342,6 +345,9 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@bitte-ai/data@0.1.0-fix-cicd2-460c6c4': + resolution: {integrity: sha512-b3hmiSbimQMHaDD2ZmahVX6zTBxs2rsRnMEJDTuPA/I6Docu706xHfSAycLy5jkXz+Z2ukdjV7p8Ap/FnLLvvQ==} + '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} @@ -698,6 +704,18 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@prisma/client@6.4.1': + resolution: {integrity: sha512-A7Mwx44+GVZVexT5e2GF/WcKkEkNNKbgr059xpr5mn+oUm2ZW1svhe+0TRNBwCdzhfIZ+q23jEgsNPvKD9u+6g==} + engines: {node: '>=18.18'} + peerDependencies: + prisma: '*' + typescript: '>=5.1.0' + peerDependenciesMeta: + prisma: + optional: true + typescript: + optional: true + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -3778,6 +3796,13 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@bitte-ai/data@0.1.0-fix-cicd2-460c6c4(typescript@5.7.3)': + dependencies: + '@prisma/client': 6.4.1(typescript@5.7.3) + transitivePeerDependencies: + - prisma + - typescript + '@emnapi/runtime@1.3.1': dependencies: tslib: 2.8.1 @@ -4189,6 +4214,10 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@prisma/client@6.4.1(typescript@5.7.3)': + optionalDependencies: + typescript: 5.7.3 + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -5383,7 +5412,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.0(eslint@9.20.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.20.0(jiti@1.21.7)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.0(eslint@9.20.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.0(jiti@1.21.7)))(eslint@9.20.0(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: @@ -5405,7 +5434,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.20.0(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.24.0(eslint@9.20.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.20.0(jiti@1.21.7)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.24.0(eslint@9.20.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.20.0(jiti@1.21.7)))(eslint@9.20.0(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From 8eb2d02e5d8a18e618a6e7c021be89bae45e2800 Mon Sep 17 00:00:00 2001 From: Till <till.friesewinkel@googlemail.com> Date: Fri, 14 Mar 2025 15:30:42 +0000 Subject: [PATCH 2/2] Important FIXME note, do not merge until resolved --- app/api/agents/route.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/api/agents/route.ts b/app/api/agents/route.ts index ec879be..a66034a 100644 --- a/app/api/agents/route.ts +++ b/app/api/agents/route.ts @@ -20,6 +20,7 @@ export async function GET(request: NextRequest) { limit, category: category === "" ? undefined : category, }); + // FIXME: wait for version that is camel case const sqlAgents = await listAiAgents(); const agents = [...firestoreAgents, ...sqlAgents];