Skip to content

Processors

personaforge/processors is a Mastra-style inspired processor pipeline. Input/output/error processors transform, validate, and control messages as they flow through an agent. Combined with the built-in guardrail processors, they form the security + quality layer of the runtime.

ts
import { ModerationProcessor, TokenLimiter, PIIDetector } from 'personaforge/processors';

Quick start

Attach processors to an agent at creation time:

ts
import { agent } from 'personaforge';
import {
  TokenLimiter,
  PIIDetector,
  ModerationProcessor,
  PromptInjectionDetector,
} from 'personaforge/processors';

const bot = agent({
  instructions: 'You are a helpful assistant.',
  inputProcessors: [
    new TokenLimiter(64_000),                       // cap input size
    new PIIDetector({ strategy: 'redact' }),        // redact PII
    new PromptInjectionDetector({ strategy: 'block' }),
    new ModerationProcessor({ strategy: 'block' }), // content moderation
  ],
});

You can also override processors per run — per-call arrays replace the agent-level arrays for that run only:

ts
await bot.run('Tell me a story', {
  processors: {
    input: [new TokenLimiter(10_000)],
    output: [new EnsureFinalResponse()],
  },
});

Processor stages

A ProcessorSet has three phases:

PhaseRuns whenTypical use
inputBefore messages reach the LLMToken caps, PII redaction, moderation, injection defense
outputAfter the LLM respondsValidate answer shape, final-response enforcement, cache writes
errorProvider rejects a requestRetry with recovery messages

Within a processor, several hooks fire at specific points (input, input-step, LLM-request, LLM-response, output-step, output-result, output-stream, API-error). A processor coordinates between its own hooks via a per-request state scratchpad.

Processors can abort() (throw a TripWireError) to block a request, sendSignal() to inject a <system-reminder> user message, and reuse per-request state across hooks.


Built-in processors

ProcessorWhat it does
TokenLimiterCaps input tokens (block/warn)
UnicodeNormalizerNormalizes unicode in messages
ToolCallFilterAllows/blocks tool calls by name
PIIDetectorDetects / redacts / blocks PII
PromptInjectionDetectorDetects / blocks prompt-injection patterns
ModerationProcessorContent moderation (block/warn/detect)
CostGuardProcessorBudgets request cost
LanguageDetectorDetects message language
BatchPartsProcessorBatches multimodal parts
SystemPromptScrubberStrips secrets from system prompts
ResponseCacheCaches LLM responses by prompt
EnsureFinalResponseForces a final answer after max steps
ContextLengthHandlerHandles context overflow

LLM-backed processors accept an optional classify function so you can plug in any model judge; deterministic heuristic implementations are used by default (zero extra calls).


Writing a custom processor

A processor is any object implementing the Processor interface — implement one or more hooks; id must be unique (it scopes the per-request state):

ts
import type { Processor, ProcessInputArgs } from 'personaforge/processors';

const myChecker: Processor = {
  id: 'my-checker',

  async processInput({ messages, abort }: ProcessInputArgs) {
    for (const m of messages) {
      if (typeof m.content === 'string' && m.content.includes('secret:')) {
        abort('Contains forbidden content', { metadata: { match: 'secret:' } });
      }
    }
    return messages;
  },
};

Other hooks: processInputStep, processLLMRequest, processLLMResponse, processOutputStep, processOutputStream, processOutputResult, and processAPIError.


  • Guardrails — the guardrail module (rules + validators).
  • Memory — memory processors (MessageHistoryProcessor, …).
  • Production — resilience and safety in production.

Released under the MIT License.