Graduation Project β Faculty of Computers and Artificial Intelligence, Cairo University
A robust NestJS backend service acting as the Backend-for-Frontend (BFF) for the AutoPipeline AI Agent. It bridges the Electron desktop client and the Python multi-agent system, managing conversation state, NDJSON stream proxying, human-in-the-loop (HITL) event merging, and LLM model catalogs without requiring database persistence on the Python Agent.
- Backend-for-Frontend (BFF) Architecture β Decouples the frontend UI from the AI Agent. Manages session persistence, API key isolation, and model discovery cleanly.
- NDJSON Stream Proxying & Resilience β Intercepts real-time NDJSON event streams from the Agent, updates session titles dynamically on
title.generatedevents, and forwards all events (includingllm.errorprovider errors) to the client. Safely guards JSON parsing against malformed lines so stream connections never crash. - Reliable Message Persistence β Persists user messages before stream execution begins to prevent input loss during network interruptions. Automatically extracts human-readable text from stored
ASSISTANTevent arrays so the LLM receives clean conversation history. - Human-in-the-Loop (HITL) Event Merging β Manages permission gating and clarification interruptions by appending continuation events directly to existing assistant messages, presenting a continuous event timeline to the UI.
- Platform-Aware SQLite Storage β Automatically resolves database file paths across Windows (
AppData/Local), macOS (Library/Application Support), and Linux (~/.config), ensuring seamless desktop app integration. - Dynamic Model Catalog & Custom Providers β Auto-fetches curated LLM models from public registries (
models.dev) on startup and allows users to register custom OpenAI-compatible endpoints and models.
| Layer | Technology |
|---|---|
| Framework | NestJS v11 + Express |
| Database | SQLite 3 (better-sqlite3) |
| ORM | Prisma v7 |
| Language | TypeScript 5 |
| Runtime | Node.js β₯ 20 |
git clone <repo-url>
cd backend
npm installCreate a .env file in the project root (optional β sensible defaults apply). Only the following variables are read from the environment:
PORT=3000
AGENT_URL="http://localhost:8000"
# Optional stream tuning (milliseconds):
# AGENT_CONNECT_TIMEOUT_MS=100000
# AGENT_STREAM_IDLE_TIMEOUT_MS=300000Note: The SQLite database path is not configured via
DATABASE_URL. It is resolved automatically per-OS bygetDbPath()(src/config/database.config.ts) and always takes precedence over any environment value.
npx prisma generate
npx prisma migrate deploy# Development mode with hot-reload
npm run start:dev
# Production build
npm run build
npm run start:prodThe server starts at http://localhost:3000.
Start a new CI/CD pipeline generation stream:
projectId and modelId are the UUIDs returned by POST /projects and GET /models. If sessionId is omitted, a new session is created automatically.
curl -N -X POST "http://localhost:3000/messages?projectId=f9fbea4f-956a-4cdb-bae2-358f86c84e96&modelId=705e4c73-5a74-40d0-a68b-015c83e40980" \
-H "Content-Type: application/json" \
-d '{
"message": "Create a GitHub Actions CI pipeline for this NestJS app",
"apikey": "AIzaSy...",
"targetPlatform": "github_actions",
"reasoningEffort": "medium"
}'The system follows a modular NestJS BFF pattern where specialized modules handle state while MessagesModule acts as a streaming proxy to the Python Agent:
ββββββββββββββββββββββββββ
β NESTJS BFF LAYER β
β (State & Streaming) β
ββββ¬ββββ¬ββββββββββ¬ββββ¬ββββ
β β β β
βββββββ β β βββββββ
βΌ βΌ βΌ βΌ
Projects Sessions Messages Models
Module Module Module Module
β β ββββ΄βββ β
ββββββββββββΌβββββββ€Prismaββββββββ
β ββββ¬βββ
βΌ βΌ
Python Agent SQLite DB
(/generate/stream) (dev.db)
ProjectsModuleβ Registers local project directories with filesystem validation and birthtime-based deduplication. (The CI/CD platform target,github_actionsorgitlab_ci, is chosen per-message via thetargetPlatformfield, not stored on the project.)SessionsModuleβ Manages conversation sessions. Note that sessions are auto-created byMessagesServicewhen sending the first message.MessagesModuleβ Intercepts NDJSON streams, manages HITL flows (sendPermissionandsendClarification), and handles reliable database persistence.ModelModuleβ Catalogs LLM providers and models, synchronizing with remote model catalogs.DatabaseModuleβ Global Prisma ORM service with platform-aware SQLite storage resolution.
| Method | Endpoint | Description |
|---|---|---|
POST |
/projects |
Create or return an existing project by directory path |
GET |
/projects |
List all initialized projects |
GET |
/sessions?projectId={id} |
List all sessions for a project |
GET |
/sessions/:id |
Get session details |
DELETE |
/sessions/:id |
Delete a session and all its messages |
DELETE |
/sessions?projectId={id} |
Delete all sessions for a project |
POST |
/messages?projectId=&sessionId=&modelId= |
Send a prompt and stream NDJSON events from Agent |
POST |
/messages/permission?sessionId=&modelId= |
Submit HITL command permission decision (allow/deny) |
POST |
/messages/clarification?sessionId=&modelId= |
Submit answer to an Agent clarification question |
POST |
/messages/cancel |
Cancel an active Agent run (body: { "runId": "..." }) |
GET |
/messages?sessionId={id} |
Get conversation message history for a session |
GET |
/messages/:id |
Get a single message by ID |
GET |
/models |
List all available LLM providers and models |
GET |
/models/:id |
Get a single model by ID |
POST |
/models |
Register a custom OpenAI-compatible model |
PATCH |
/models/:id |
Update a custom (openai_compatible) model |
DELETE |
/models/:id |
Delete a custom (openai_compatible) model |
For comprehensive technical documentation covering architecture deep-dives, module-by-module breakdowns, NDJSON streaming protocol details, database schemas, and design trade-offs, see:
π Full Technical Documentation
# Run unit tests
npm run test
# Run tests in watch mode
npm run test:watch
# Run test coverage report
npm run test:covMIT