From 4d2fab827d8ad34c4d8823e9dd0e66ee0345c288 Mon Sep 17 00:00:00 2001 From: Harsh-Duche Date: Thu, 27 Nov 2025 18:19:14 +0530 Subject: [PATCH] feat: add runAgent functionality to execute agent commands and update user credit balance --- .../20251127123756_ag_credits/migration.sql | 3 ++ prisma/schema.prisma | 4 +- src/controllers/agent.controller.ts | 22 +++++++-- src/routes/agent.route.ts | 1 + src/services/agent.service.ts | 47 +++++++++++++++++-- 5 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 prisma/migrations/20251127123756_ag_credits/migration.sql diff --git a/prisma/migrations/20251127123756_ag_credits/migration.sql b/prisma/migrations/20251127123756_ag_credits/migration.sql new file mode 100644 index 0000000..4f6ab16 --- /dev/null +++ b/prisma/migrations/20251127123756_ag_credits/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "user" ADD COLUMN "creditBalance" DOUBLE PRECISION NOT NULL DEFAULT 100, +ADD COLUMN "creditBalanceLastUpdated" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index af7aab6..485a555 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -13,12 +13,14 @@ model user { email String @unique emailVerified Boolean image String? - nonce String? createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @default(now()) @db.Timestamptz(6) + nonce String? agent agent[] apikey apikey[] walletAddress walletAddress? + creditBalance Float @default(100) + creditBalanceLastUpdated DateTime @db.Timestamptz(6) @default(now()) } model walletAddress { diff --git a/src/controllers/agent.controller.ts b/src/controllers/agent.controller.ts index 0f1fb58..cd67205 100644 --- a/src/controllers/agent.controller.ts +++ b/src/controllers/agent.controller.ts @@ -92,16 +92,28 @@ export class AgentController { } } - public static readonly verifyAgent = async(c: Context) => { + public static readonly runAgent = async (c: Context) => { try { - const { deployedUrl, default_agent_name } =(await c.req.json()) as IAgentNameVerification; + const agent_id = c.req.param('id'); + const { message } = await c.req.json(); + const user = await c.get('user'); + const agent = await AgentService.runAgent(agent_id.trim(), message.trim(), user?.id); + return c.json(api_response({ message: "Agent response", data: agent })); + } catch (error) { + return c.json(api_response({ message: `Failed to run agent: ${getErrorMessage(error)}`, is_error: true }), 500); + } + } + + public static readonly verifyAgent = async (c: Context) => { + try { + const { deployedUrl, default_agent_name } = (await c.req.json()) as IAgentNameVerification; if (!deployedUrl && !default_agent_name) { return c.json(api_response({ message: 'deployedUrl and default_agent_name are required' }), 400); } await AgentService.verifyAgent(deployedUrl, default_agent_name); return c.json(api_response({ message: 'Agent URL verified successfully', data: true }), 200); } catch (error) { - if(error instanceof Error) { + if (error instanceof Error) { return c.json(api_response({ message: error.message, data: false, is_error: true }), 500); } } @@ -245,7 +257,7 @@ export class AgentController { } // Validate numeric fields - const numericCost = parseFloat(agentCost); + const numericCost = parseFloat(agentCost.toString()); if (isNaN(numericCost) || numericCost < 0) { return c.json( api_response({ @@ -272,7 +284,7 @@ export class AgentController { const agent = await AgentService.createAgent(user.id, { name: name.trim(), description: description.trim(), - agentCost, + agentCost: agentCost.toString(), deployedUrl: deployedUrl.trim(), llmProvider: llmProvider.trim(), skills: skills.map(skill => skill.trim()), diff --git a/src/routes/agent.route.ts b/src/routes/agent.route.ts index a15acd1..483626f 100644 --- a/src/routes/agent.route.ts +++ b/src/routes/agent.route.ts @@ -8,6 +8,7 @@ app.post("/", verifyApiKey, AgentController.primary); app.post("/verify", AgentController.verifyAgent); app.post("/create", AgentController.createAgent); app.get("/all", AgentController.getAllAgents); +app.post("/:id/run", AgentController.runAgent); app.get("/:id", AgentController.getAgent); app.put("/:id", AgentController.updateAgent); app.delete("/:id", AgentController.deleteAgent); diff --git a/src/services/agent.service.ts b/src/services/agent.service.ts index 8024573..08764e9 100644 --- a/src/services/agent.service.ts +++ b/src/services/agent.service.ts @@ -63,7 +63,7 @@ export class AgentService { matched_agents[0].deployedUrl, matched_agents[0].default_agent_name || "", (matched_agents[0].framework_used as AgentFrameWorks) || - AgentFrameWorks.google_adk, + AgentFrameWorks.google_adk, data.message, session_id, api_key.userId @@ -91,6 +91,47 @@ export class AgentService { } }; + public static readonly runAgent = async (agent_id: string, message: string, user_id: string) => { + const agent = await prisma.agent.findUnique({ + where: { id: agent_id }, + }); + if (!agent) { + throw new Error("Agent not found"); + } + const session_id = crypto.randomUUID(); + + const response = await callProxiedAgent( + agent.deployedUrl, + agent.default_agent_name || "", + (agent.framework_used as AgentFrameWorks) || AgentFrameWorks.google_adk, + message, + session_id, + user_id + ); + + await prisma.user.update({ + where: { id: user_id }, + data: { + creditBalance: { + decrement: Number(agent.agentCost) + (agent.inputTokenCost > 0 ? Number(agent.inputTokenCost) * (response.input_tokens || 0) : 0) + (agent.outputTokenCost > 0 ? Number(agent.outputTokenCost) * (response.output_tokens || 0) : 0), + }, + creditBalanceLastUpdated: new Date(), + }, + }); + + const user = await prisma.user.findUnique({ + where: { id: user_id }, + }); + if (!user) { + throw new Error("User not found"); + } + + return { + response: response.response_content, + creditBalance: user.creditBalance, + }; + } + public static readonly verifyAgent = async ( uri: string, agent_name: string @@ -268,7 +309,7 @@ export class AgentService { ) => { // First check if the agent exists and user has permission const existingAgent = await prisma.agent.findUnique({ - where: { id: agent_id }, + where: { id: agent_id, userId: user_id }, }); if (!existingAgent) { @@ -280,7 +321,7 @@ export class AgentService { } const agent = await prisma.agent.delete({ - where: { id: agent_id }, + where: { id: agent_id, userId: user_id }, }); return agent;