-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add runAgent functionality to execute agent commands and update… #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| const agent = await AgentService.runAgent(agent_id.trim(), message.trim(), user?.id); | |
| if (!user || !user.id) { | |
| return c.json( | |
| api_response({ | |
| message: "User authentication required", | |
| is_error: true | |
| }), | |
| 401 | |
| ); | |
| } | |
| const agent = await AgentService.runAgent(agent_id.trim(), message.trim(), user.id); |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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"); | ||||||||||||||
| } | ||||||||||||||
|
||||||||||||||
| } | |
| } | |
| // Check if user can access this agent | |
| if (!agent.isPublic && agent.userId !== user_id) { | |
| throw new Error("Unauthorized to run this agent"); | |
| } |
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No check for sufficient credit balance before running the agent. The service will decrement the user's credit balance without first verifying that they have sufficient credits. This could result in negative credit balances. Add a check to ensure the user has enough credits before calling the agent:
const user = await prisma.user.findUnique({
where: { id: user_id },
});
if (!user) {
throw new Error("User not found");
}
const estimatedCost = Number(agent.agentCost) +
(agent.inputTokenCost > 0 ? Number(agent.inputTokenCost) * 1000 : 0) + // Estimate max tokens
(agent.outputTokenCost > 0 ? Number(agent.outputTokenCost) * 1000 : 0);
if (user.creditBalance < estimatedCost) {
throw new Error("Insufficient credit balance");
}
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complex credit calculation embedded in update statement reduces maintainability. The inline credit calculation is difficult to read, debug, and test. Extract this calculation into a separate, testable function:
const calculateAgentCost = (
agent: { agentCost: string; inputTokenCost: number; outputTokenCost: number },
response: { input_tokens: number | null; output_tokens: number | null }
): number => {
const baseCost = Number(agent.agentCost);
const inputCost = agent.inputTokenCost > 0
? Number(agent.inputTokenCost) * (response.input_tokens || 0)
: 0;
const outputCost = agent.outputTokenCost > 0
? Number(agent.outputTokenCost) * (response.output_tokens || 0)
: 0;
return baseCost + inputCost + outputCost;
};
// Then use it in the update:
const totalCost = calculateAgentCost(agent, response);
await prisma.user.update({
where: { id: user_id },
data: {
creditBalance: { decrement: totalCost },
creditBalanceLastUpdated: new Date(),
},
});
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Risk of race condition in credit balance update. The credit balance is read after the agent call and update operation, which could lead to stale data if multiple concurrent requests are made. The balance could be decremented multiple times before the user query returns the updated value. Consider using an atomic transaction or returning the updated user data from the update operation:
const updatedUser = await prisma.user.update({
where: { id: user_id },
data: {
creditBalance: {
decrement: /* credit calculation */,
},
creditBalanceLastUpdated: new Date(),
},
});
return {
response: response.response_content,
creditBalance: updatedUser.creditBalance,
};
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid Prisma where clause. Prisma's where clause on findUnique requires a unique constraint, but the agent model only has id as a unique field, not a compound (id, userId) constraint. This will cause a runtime error. The authorization check on line 319 is already sufficient, so the where clause should only use id:
const existingAgent = await prisma.agent.findUnique({
where: { id: agent_id },
});
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid Prisma where clause. Same issue as in findUnique above - Prisma's delete requires a unique constraint, but (id, userId) is not a compound unique key. Use only id:
const agent = await prisma.agent.delete({
where: { id: agent_id },
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing input validation for required parameters. The
agent_idandmessageparameters are not validated before use. Add validation to ensure these required fields exist and are non-empty strings, similar to other endpoints likedeleteAgent: