Intégration NestJS
@orka-js/nestjs — Agents IA enterprise avec l'IoC NestJS
La première intégration NestJS vraiment idiomatique pour les agents IA. Exposez les agents via DI, décorateurs, guards, pipes, CQRS et transports microservices — avec les patterns que vous connaissez déjà.
Ce qui est inclus
OrkaModule DI
forRoot / forRootAsync / forMicroservice — pattern NestJS DynamicModule standard avec support ConfigService.
@OrkaAgent & @InjectAgent
Décorateurs pour marquer et injecter des agents n'importe où dans votre graphe DI — services, controllers, guards.
@AgentReact (Event-Driven)
Décorateur de méthode qui délègue automatiquement n'importe quel @OnEvent() à un agent. Zéro boilerplate.
OrkaSemanticGuard
Guard CanActivate alimenté par LLM. Décrivez votre politique en anglais — le LLM décide ALLOW ou DENY.
AgentValidationPipe
PipeTransform qui accepte du langage naturel et retourne un DTO typé via llm.generateObject().
CQRS + Microservices
OrkaQueryHandler, @AgentQueryHandler, OrkaMessageHandler, AgentClient — patterns enterprise complets.
Installation
npm install @orka-js/nestjs# orpnpm add @orka-js/nestjs # Optional — install only what you use:npm install @nestjs/cqrs # For CQRS featuresnpm install @nestjs/microservices # For microservice transportConfiguration du module
Importez OrkaModule dans votre AppModule. Tous les agents sont auto-enregistrés comme providers DI nommés.
// app.module.tsimport { Module } from '@nestjs/common';import { OrkaModule } from '@orka-js/nestjs';import { Agent } from '@orka-js/agent';import { AnthropicAdapter } from '@orka-js/anthropic'; const llm = new AnthropicAdapter({ apiKey: process.env.ANTHROPIC_API_KEY! }); const salesAgent = new Agent({ goal: 'Sales assistant', tools: [] }, llm);const supportAgent = new Agent({ goal: 'Support assistant', tools: [] }, llm); @Module({ imports: [ OrkaModule.forRoot({ agents: { sales: salesAgent, support: supportAgent, }, path: 'ai', // Routes at: /ai, /ai/:agent, /ai/:agent/stream }), ],})export class AppModule {}Config asynchrone (avec ConfigService)
Utilisez forRootAsync quand vos clés LLM viennent des variables d'environnement via ConfigService.
// app.module.tsimport { Module } from '@nestjs/common';import { ConfigModule, ConfigService } from '@nestjs/config';import { OrkaModule } from '@orka-js/nestjs';import { Agent } from '@orka-js/agent';import { AnthropicAdapter } from '@orka-js/anthropic'; @Module({ imports: [ ConfigModule.forRoot(), OrkaModule.forRootAsync({ imports: [ConfigModule], path: 'ai', useFactory: (config: ConfigService) => ({ agents: { assistant: new Agent( { goal: 'Helpful assistant', tools: [] }, new AnthropicAdapter({ apiKey: config.get('ANTHROPIC_API_KEY')! }) ), }, }), inject: [ConfigService], }), ],})export class AppModule {}Routes HTTP auto-générées
Quand path est défini dans OrkaModule.forRoot(), OrkaJS monte automatiquement ces routes :
| Method | Path | Description |
|---|---|---|
| GET | /{path} | Liste tous les agents enregistrés |
| GET | /{path}/:agent | Informations sur l'agent |
| POST | /{path}/:agent | Exécuter l'agent (sans streaming) |
| POST | /{path}/:agent/stream | Exécuter avec SSE streaming |
Décorateurs
Injectez des agents n'importe où dans votre application. Utilisez @OrkaAgent pour marquer les classes avec des métadonnées.
// order.service.tsimport { Injectable } from '@nestjs/common';import { InjectAgent } from '@orka-js/nestjs';import type { BaseAgent } from '@orka-js/agent'; @Injectable()export class OrderService { constructor( @InjectAgent('sales') private salesAgent: BaseAgent, @InjectAgent('support') private supportAgent: BaseAgent, ) {} async processOrder(description: string) { return this.salesAgent.run(description); } async handleComplaint(issue: string) { return this.supportAgent.run(issue); }}@AgentReact — Agents Event-Driven
Décorez n'importe quelle méthode @OnEvent() pour déléguer automatiquement le payload à un agent.
// order-events.handler.tsimport { Injectable } from '@nestjs/common';import { OnEvent } from '@nestjs/event-emitter';import { InjectAgent, AgentReact } from '@orka-js/nestjs';import type { BaseAgent } from '@orka-js/agent'; @Injectable()export class OrderEventsHandler { constructor( @InjectAgent('fulfillment') private agent: BaseAgent, @InjectAgent('retention') private retentionAgent: BaseAgent, ) {} // Awaits the agent result @OnEvent('order.created') @AgentReact() async onOrderCreated(payload: OrderCreatedEvent) {} // Fire-and-forget — doesn't block the event loop @OnEvent('customer.churned') @AgentReact({ agent: 'retentionAgent', async: true }) onCustomerChurned(payload: ChurnEvent): void {}}OrkaSemanticGuard
Protégez les routes avec une autorisation sémantique alimentée par LLM. Échoue fermé si le LLM est indisponible.
// admin.controller.tsimport { Controller, Get, UseGuards } from '@nestjs/common';import { OrkaSemanticGuard } from '@orka-js/nestjs';import { AnthropicAdapter } from '@orka-js/anthropic'; const llm = new AnthropicAdapter({ apiKey: process.env.ANTHROPIC_API_KEY! }); @Controller('admin')@UseGuards( new OrkaSemanticGuard( llm, 'Only allow requests that include a valid Authorization header with an admin Bearer token' ))export class AdminController { @Get('dashboard') getDashboard() { return { stats: '...' }; }} // The guard asks the LLM: "Based on the policy, should this request be ALLOWED or DENIED?"// → Fails closed (returns false) if the LLM is unavailableAgentValidationPipe — NLP → DTO
Acceptez du langage naturel depuis les clients et extrayez des données structurées. Retour direct à la validation de schéma pour les inputs structurés (pas de coût LLM).
// products.controller.tsimport { Controller, Post, Body } from '@nestjs/common';import { AgentValidationPipe } from '@orka-js/nestjs';import { AnthropicAdapter } from '@orka-js/anthropic';import { z } from 'zod'; const llm = new AnthropicAdapter({ apiKey: process.env.ANTHROPIC_API_KEY! }); const SearchSchema = z.object({ category: z.string(), color: z.string().optional(), maxPrice: z.number().optional(), size: z.string().optional(),}); @Controller('products')export class ProductsController { @Post('search') async search( @Body(new AgentValidationPipe(SearchSchema, llm, { description: 'product search filters' })) query: z.infer<typeof SearchSchema> ) { return this.productService.search(query); }} // Client sends: { "input": "red shoes under $50 in size 42" }// Pipe returns: { category: "shoes", color: "red", maxPrice: 50, size: "42" } // Client sends: { "category": "shoes", "color": "red" }// Pipe validates directly — no LLM call (zero cost)Intégration CQRS
Connectez directement des agents à des queries et commands CQRS. Nécessite @nestjs/cqrs.
// Import from the /cqrs sub-path (requires @nestjs/cqrs)import { OrkaQueryHandler, AgentQueryHandler } from '@orka-js/nestjs/cqrs';import { InjectAgent } from '@orka-js/nestjs';import type { BaseAgent } from '@orka-js/agent'; // 1. Define the queryexport class GetProductRecommendationsQuery { constructor(public readonly userId: string, public readonly category: string) {}} // 2. Create the handler — extends OrkaQueryHandler, zero boilerplate@AgentQueryHandler(GetProductRecommendationsQuery)export class RecommendationsHandler extends OrkaQueryHandler<GetProductRecommendationsQuery> { constructor(@InjectAgent('recommendations') protected agent: BaseAgent) { super(); } // execute() is provided by OrkaQueryHandler: // → calls agent.run(JSON.stringify(query)) automatically} // 3. Register in module@Module({ imports: [CqrsModule, OrkaModule.forRoot({ agents: { recommendations: recoAgent } })], providers: [RecommendationsHandler],})export class ProductsModule {}Agent as Microservice
Déployez des agents comme microservices NestJS indépendants — scalables, agnostiques au transport (Redis, NATS, Kafka, TCP). Nécessite @nestjs/microservices.
// Import from the /microservice sub-path (requires @nestjs/microservices)import { OrkaClientModule } from '@orka-js/nestjs/microservice';import { InjectAgentClient, AgentClient } from '@orka-js/nestjs';import { Transport } from '@nestjs/microservices'; // ── SERVER APP (agent microservice) ───────────────────────────────────────── // main.tsconst app = await NestFactory.createMicroservice(AppModule, { transport: Transport.REDIS, options: { host: 'localhost', port: 6379 },});await app.listen(); // app.module.ts@Module({ imports: [await OrkaModule.forMicroservice({ agents: { sales: salesAgent, support: supportAgent } })]})export class AppModule {} // ── CONSUMER APP ───────────────────────────────────────────────────────────── @Module({ imports: [ OrkaClientModule.forRoot({ clients: [{ name: 'agents', options: { transport: Transport.REDIS, options: { host: 'localhost', port: 6379 } }, }], }), ],})export class ConsumerModule {} @Injectable()export class OrderService { constructor(@InjectAgentClient('agents') private client: AgentClient) {} async processOrder(order: Order) { return this.client.run('sales', JSON.stringify(order)); }}📦 Dépendances peer optionnelles
Les features CQRS et microservices nécessitent des packages optionnels. Installez seulement ce dont vous avez besoin :
npm install @nestjs/cqrs # @orka-js/nestjs/cqrsnpm install @nestjs/microservices # @orka-js/nestjs/microservice