Skip to content

Repository files navigation

nestjs-agentic banner

nestjs-agentic

The NestJS-native runtime for governed AI agents
Define agents and tools with NestJS, enforce policy before side effects, and keep model integrations replaceable.

NestJS NPM Version CI Status TypeScript License

Why nestjs-agentic?

Most agent frameworks introduce a separate runtime and application boundary. nestjs-agentic keeps agent-facing capabilities inside the NestJS module and dependency-injection system:

NestJS service
    -> @ToolSet and @Tool
    -> context-bound ResolvedTool
    -> allow / deny / require_approval policy decision
    -> RuntimeAdapter

Application services remain ordinary NestJS providers. The model runtime receives governed tool closures rather than direct access to services or application-owned security context.

Current Capabilities

The current release line is 0.6.x. Core primitives, persistence adapters, and durable execution checkpoints are production-intent; higher-order orchestration packages remain experimental while their contracts stabilize.

Area Status Scope
Agents, tools, and NestJS DI Available Decorators, discovery, feature registration, and context-bound tools.
Tool governance & HITL Available allow, deny, and require_approval before execution; resumes durably via ApprovalStore.
Model Context Protocol (MCP) Available @nestjs-agentic/mcp for Stdio and SSE remote tool discovery, authorization, and execution.
Built-in runtime & Model Cascading Available Loop execution, streaming, budgets, and FrugalGPT confidence-threshold model cascading.
OpenAI & Chat-Completions adapter Available @nestjs-agentic/openai for OpenAI, Azure, Ollama, vLLM, Groq, and OpenRouter.
Cognitive Memory & SOP Playbooks Available @nestjs-agentic/memory for Stanford Tri-Factor scoring, SOP playbooks, and reflection.
U-Shaped Context Assembler Available @nestjs-agentic/rag & @nestjs-agentic/core for Lost-in-the-Middle attention mitigation.
Codebase AST & GraphRAG Available @nestjs-agentic/rag for AST code splitting, hybrid vector store, and graph traversal.
Debiased Evaluation & Trajectory Metrics Available @nestjs-agentic/evaluation for MT-Bench position-debiased judge and AgentBench metrics.
Persistence & Durable Checkpoints Available In-memory, Redis, and PostgreSQL drivers for Session, State, Approval, and Idempotency.
Sub-Agent Orchestration Available @nestjs-agentic/orchestration for parallel delegation, bounded concurrency, and refinement.

See the product roadmap for milestones and production-readiness criteria.

Packages

Package Purpose
nestjs-agentic Meta package that re-exports the core framework
@nestjs-agentic/core Agents, tools, policies, approvals, the built-in runtime, and the adapter contracts
@nestjs-agentic/mcp Model Context Protocol (MCP) client transport and tool provider
@nestjs-agentic/openai OpenAI ModelAdapter, also covering Chat Completions compatible endpoints
@nestjs-agentic/memory Stanford Tri-Factor cognitive scoring, procedural SOP playbooks, and experience reflection
@nestjs-agentic/rag Retrieval strategies, vector stores, and knowledge-graph primitives
@nestjs-agentic/orchestration Sub-agent delegation, parallel execution, and refinement loops
@nestjs-agentic/evaluation Metrics, benchmark execution, and reporting

Installation

npm install nestjs-agentic

Connect a model provider:

npm install @nestjs-agentic/openai openai

Optional packages:

npm install @nestjs-agentic/mcp
npm install @nestjs-agentic/memory
npm install @nestjs-agentic/rag @nestjs-agentic/memory
npm install @nestjs-agentic/orchestration
npm install @nestjs-agentic/evaluation

Quick Start

The example uses MockModelAdapter, so the full tool-calling loop runs deterministically without an API key. Swap in your own ModelAdapter to talk to a real provider.

1. Define a policy and tool set

import { Injectable } from '@nestjs/common';
import {
  AgentContext,
  Context,
  Param,
  PolicyResult,
  Tool,
  ToolPolicy,
  ToolSet,
  UsePolicies,
} from 'nestjs-agentic';

@Injectable()
export class RefundLimitPolicy implements ToolPolicy {
  async evaluate(
    _ctx: AgentContext,
    _toolName: string,
    args: Record<string, unknown>,
  ): Promise<PolicyResult> {
    return Number(args.amount) > 500
      ? { decision: 'require_approval', reason: 'Refund exceeds $500.' }
      : { decision: 'allow' };
  }
}

@ToolSet({ name: 'orders' })
export class OrderTools {
  @Tool({ name: 'refundOrder', description: 'Refund an order' })
  @UsePolicies(RefundLimitPolicy)
  async refundOrder(
    @Param('orderId') orderId: string,
    @Param('amount', { type: 'number' }) amount: number,
    @Context() ctx: AgentContext,
  ) {
    return { orderId, amount, requestedBy: ctx.security.userId };
  }
}

2. Define an agent and module

import { Module } from '@nestjs/common';
import {
  Agent,
  AgentConfig,
  AgenticModule,
  AgentProvider,
  MockModelAdapter,
} from 'nestjs-agentic';

@Agent({ name: 'support', description: 'Handles support requests' })
export class SupportAgent implements AgentProvider {
  constructor(private readonly orderTools: OrderTools) {}

  define(): AgentConfig {
    return {
      instructions: 'Help the user while respecting tool policies.',
      tools: [this.orderTools],
    };
  }
}

const model = new MockModelAdapter();
model
  .whenAsked('Refund $600 for order #42')
  .callTool('refundOrder', { orderId: '42', amount: 600 })
  .reply('That refund needs approval before I can complete it.');

@Module({
  imports: [
    AgenticModule.forRoot({
      defaultModel: { provider: 'mock', model: 'deterministic' },
      modelAdapter: model,
      limits: { maxIterations: 6 },
    }),
    AgenticModule.forFeature({
      agents: [SupportAgent],
      toolSets: [OrderTools],
      policies: [RefundLimitPolicy],
    }),
  ],
})
export class AppModule {}

AgenticModule.forFeature() registers these classes inside AgenticModule. Keep an agent, its tool sets, and its policies in a single forFeature() call, and export any application services they inject from a @Global() module.

3. Run the agent and handle approval

import { Body, Controller, Param, Post } from '@nestjs/common';
import { AgentRunner, ApprovalService } from 'nestjs-agentic';

@Controller('support')
export class SupportController {
  constructor(
    private readonly runner: AgentRunner,
    private readonly approvals: ApprovalService,
  ) {}

  @Post('chat')
  chat(@Body() body: { sessionId: string; message: string }) {
    return this.runner.run('support', {
      sessionId: body.sessionId,
      message: body.message,
      context: {
        userId: 'user_123',
        tenantId: 'acme',
      },
    });
  }

  @Post('approve/:id')
  approve(@Param('id') id: string) {
    return this.approvals.approve(id);
  }

  @Post('reject/:id')
  reject(@Param('id') id: string) {
    return this.approvals.reject(id);
  }
}

runner.runStream() exposes structured token, tool_start, tool_result, approval_required, and complete events.

Each run is bounded. Pass limits and a signal to cap iterations, tool calls, tokens, and wall-clock time, or to cancel work in flight:

await runner.run('support', {
  sessionId,
  message,
  limits: { maxIterations: 4, maxToolCalls: 8, timeoutMs: 30_000 },
  signal: abortController.signal,
});

Built-in Policies

  • RateLimitPolicy β€” process-local sliding-window limits by tenant, user, and tool.
  • CostLimitPolicy β€” numeric allow, approval, and deny thresholds.
  • LoggingPolicy β€” configurable tool-attempt logging with field masking.

These are framework primitives, not replacements for distributed rate limiting, durable audit storage, or application authorization.

Connecting a Model

For OpenAI and any Chat Completions compatible endpoint, use the published adapter:

import { AgenticModule } from 'nestjs-agentic';
import { OpenAiModelAdapter } from '@nestjs-agentic/openai';

AgenticModule.forRoot({
  defaultModel: { provider: 'openai', model: 'gpt-4o-mini' },
  modelAdapter: new OpenAiModelAdapter({ apiKey: process.env.OPENAI_API_KEY }),
});

The same adapter targets local and third-party servers by pointing baseUrl at them, for example http://localhost:11434/v1 for Ollama. See @nestjs-agentic/openai for Azure, reasoning models, and compatibility notes.

For any other provider, implement ModelAdapter directly. It handles only provider communication; the framework owns the loop, validation, policies, budgets, and streaming.

import type { ModelAdapter, ModelRequest, ModelResponse } from 'nestjs-agentic';

export class MyModelAdapter implements ModelAdapter {
  async generate(request: ModelRequest): Promise<ModelResponse> {
    const completion = await callProvider({
      model: request.model.model,
      messages: request.messages,
      tools: request.tools,
      signal: request.signal,
    });

    return {
      content: completion.text,
      toolCalls: completion.toolCalls,
      usage: completion.usage,
      finishReason: completion.toolCalls.length ? 'tool_calls' : 'stop',
    };
  }
}

The core package does not import external model SDKs. Custom model adapters implement ModelAdapter directly, while the framework manages loop execution, policy enforcement, budgets, and streaming.

Documentation

Runnable examples are available in examples.

Sponsorship & Support

nestjs-agentic is an open-source framework dedicated to production-grade, governed AI agent systems in NestJS. If you or your organization find value in the project, consider supporting ongoing development:

License

MIT Β© irzix

About

The NestJS-native runtime for governed AI agents

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

87 stars

Watchers

4 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages