Spaces:
Paused
Paused
Download src/agent/agent.controller.ts from IlyasDaoud/omnia-agent-api: direct link, hf CLI and curl.
- Browser
- Download file 3.08 kB
-
https://huggingface.co/spaces/IlyasDaoud/omnia-agent-api/resolve/main/src/agent/agent.controller.ts
- Command line
-
hf download hf://spaces/IlyasDaoud/omnia-agent-api/src/agent/agent.controller.ts
-
curl -L -o agent.controller.ts https://huggingface.co/spaces/IlyasDaoud/omnia-agent-api/resolve/main/src/agent/agent.controller.ts
3.08 kB
| import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res, UseGuards } from '@nestjs/common'; | |
| import { SkipThrottle, Throttle } from '@nestjs/throttler'; | |
| import type { Request, Response } from 'express'; | |
| import type { User } from '@prisma/client'; | |
| import { AgentService } from './agent.service'; | |
| import { UsageService, type UsageSnapshot } from './usage.service'; | |
| import { RunAgentDto } from './dto/run-agent.dto'; | |
| import { OptionalAuthGuard } from '../auth/optional-auth.guard'; | |
| import { CurrentUser } from '../auth/current-user.decorator'; | |
| import { trackerKey } from '../common/tracker-key'; | |
| ('agent') | |
| export class AgentController { | |
| constructor( | |
| private readonly agent: AgentService, | |
| private readonly usage: UsageService, | |
| ) {} | |
| /** | |
| * GET /agent/usage — how many agent requests this user/IP has left this minute | |
| * and today, for the UI meter. Read-only, so it's exempt from throttling. | |
| */ | |
| () | |
| ('usage') | |
| getUsage(() req: Request): Promise<UsageSnapshot> { | |
| return this.usage.snapshot(trackerKey(req)); | |
| } | |
| /** | |
| * POST /agent/run — streams the agent loop as Server-Sent Events. | |
| * Public (OptionalAuthGuard): runs anonymously, personalizes & persists when | |
| * a valid Clerk token is supplied. Emits one JSON AgentEvent per SSE frame, | |
| * terminated by `data: [DONE]`. | |
| */ | |
| // The agent loop makes paid Groq calls — cap it tightly per user-or-IP so it | |
| // can't be spammed. 20/min (throttler) + a daily cap (UsageService) below. | |
| ({ default: { ttl: 60_000, limit: 20 } }) | |
| ('run') | |
| (OptionalAuthGuard) | |
| async run( | |
| () dto: RunAgentDto, | |
| () user: User | null, | |
| () req: Request, | |
| () res: Response, | |
| ): Promise<void> { | |
| // Daily cap (the throttler only enforces the per-minute window). Persisted in | |
| // Postgres so it survives restarts. Count this run against the user/IP bucket. | |
| const key = trackerKey(req); | |
| if (await this.usage.isDayExceeded(key)) { | |
| throw new HttpException('Daily request limit reached. Please try again tomorrow.', HttpStatus.TOO_MANY_REQUESTS); | |
| } | |
| await this.usage.record(key); | |
| res.setHeader('Content-Type', 'text/event-stream'); | |
| res.setHeader('Cache-Control', 'no-cache, no-transform'); | |
| res.setHeader('Connection', 'keep-alive'); | |
| res.setHeader('X-Accel-Buffering', 'no'); // disable proxy buffering (nginx) | |
| res.flushHeaders(); | |
| let clientGone = false; | |
| req.on('close', () => { | |
| clientGone = true; | |
| }); | |
| try { | |
| for await (const event of this.agent.run( | |
| { | |
| prompt: dto.prompt, | |
| history: dto.history ?? [], | |
| provider: dto.provider, | |
| conversationId: dto.conversationId, | |
| location: dto.location, | |
| account: dto.account, | |
| }, | |
| user, | |
| )) { | |
| if (clientGone) break; | |
| res.write(`data: ${JSON.stringify(event)}\n\n`); | |
| } | |
| } finally { | |
| if (!clientGone) { | |
| res.write('data: [DONE]\n\n'); | |
| res.end(); | |
| } | |
| } | |
| } | |
| } | |