# Message Length Limiter

This example shows how to create a custom input processor that validates and limits the total length of messages before they are sent to the language model. This processor helps prevent expensive API calls and ensures consistent input constraints across your application.

## Create a custom input processor

A custom input processor in Mastra implements the `Processor` interface with the `processInput` method. This processor validates the total character count of all text content in the message thread and blocks requests that exceed the configured limit.

```typescript title="src/mastra/processors/message-length-limiter.ts" showLineNumbers copy
import type { Processor } from '@mastra/core/processors';
import type { MastraMessageV2 } from '@mastra/core/agent/message-list';
import { TripWire } from '@mastra/core/agent';

type MessageLengthLimiterOptions = {
  maxLength?: number;
  strategy?: 'block' | 'warn' | 'truncate';
};

export class MessageLengthLimiter implements Processor {
  readonly id = 'message-length-limiter';
  readonly name = 'Message Length Limiter';
  private maxLength: number;
  private strategy: 'block' | 'warn' | 'truncate';

  constructor(options: MessageLengthLimiterOptions | number = {}) {
    if (typeof options === 'number') {
      this.maxLength = options;
      this.strategy = 'block';
    } else {
      this.maxLength = options.maxLength ?? 1000;
      this.strategy = options.strategy ?? 'block';
    }
  }

  processInput({
    messages,
    abort,
  }: {
    messages: MastraMessageV2[];
    abort: (reason?: string) => never;
  }): MastraMessageV2[] {
    try {
      const totalLength = messages.reduce((sum, msg) => {
        return (
          sum +
          msg.content.parts
            .filter(part => part.type === 'text')
            .reduce((partSum, part) => partSum + (part.type === 'text' ? part.text.length : 0), 0)
        );
      }, 0);

      if (totalLength > this.maxLength) {
        switch (this.strategy) {
          case 'block':
            abort(`Message too long: ${totalLength} characters (max: ${this.maxLength})`);
            break;
          case 'warn':
            console.warn(
              `Warning: Message length ${totalLength} exceeds recommended limit of ${this.maxLength} characters`,
            );
            break;
          case 'truncate':
            return this.truncateMessages(messages, this.maxLength);
        }
      }
    } catch (error) {
      if (error instanceof TripWire) {
        throw error;
      }
      throw new Error(`Length validation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }

    return messages;
  }

  private truncateMessages(messages: MastraMessageV2[], maxLength: number): MastraMessageV2[] {
    const truncatedMessages = [...messages];
    let currentLength = 0;

    for (let i = 0; i < truncatedMessages.length; i++) {
      const message = truncatedMessages[i];
      const parts = [...message.content.parts];

      for (let j = 0; j < parts.length; j++) {
        const part = parts[j];
        if (part.type === 'text') {
          const partLength = part.text.length;

          if (currentLength + partLength > maxLength) {
            const remainingChars = maxLength - currentLength;
            if (remainingChars > 0) {
              part.text = part.text.substring(0, remainingChars) + '...';
            } else {
              parts.splice(j);
              break;
            }
            currentLength = maxLength;
            break;
          }
          currentLength += partLength;
        }
      }

      truncatedMessages[i] = {
        ...message,
        content: { ...message.content, parts },
      };

      if (currentLength >= maxLength) {
        truncatedMessages.splice(i + 1);
        break;
      }
    }

    return truncatedMessages;
  }
}
```

### Key components

- **Constructor**: Accepts options object or number
- **Strategy options**: Choose how to handle length violations:
  - `'block'`: Reject the entire input with an error (default)
  - `'warn'`: Log warning but allow content through
  - `'truncate'`: Shorten messages to fit within the limit
- **processInput**: Validates total message length and applies the chosen strategy
- **Error handling**: Distinguishes between TripWire errors (validation failures) and application errors

### Using the processor

Using the options object approach with explicit strategy configuration:

```typescript title="src/mastra/agents/blocking-agent.ts" showLineNumbers copy
import { Agent } from '@mastra/core/agent';
import { MessageLengthLimiter } from '../processors/message-length-limiter';

export const blockingAgent = new Agent({
  id: 'blocking-agent',
  name: 'Blocking Agent',
  instructions: 'You are a helpful assistant with input length limits',
  model: 'openai/gpt-5.1',
  inputProcessors: [new MessageLengthLimiter({ maxLength: 2000, strategy: 'block' })],
});
```

Using the simple number approach (defaults to 'block' strategy):

```typescript title="src/mastra/agents/simple-agent.ts" showLineNumbers copy
import { Agent } from '@mastra/core/agent';
import { MessageLengthLimiter } from '../processors/message-length-limiter';

export const simpleAgent = new Agent({
  id: 'simple-agent',
  name: 'Simple Agent',
  instructions: 'You are a helpful assistant',
  model: 'openai/gpt-5.1',
  inputProcessors: [new MessageLengthLimiter(500)],
});
```

## High example (within limits)

This example shows a message that stays within the configured character limit and processes successfully.

```typescript title="src/example-high-message-length.ts" showLineNumbers copy
import { Agent } from '@mastra/core/agent';
import { MessageLengthLimiter } from './mastra/processors/message-length-limiter';

// Create agent with generous character limit
export const agent = new Agent({
  id: 'length-limited-agent',
  name: 'Length Limited Agent',
  instructions: 'You are a helpful assistant',
  model: 'openai/gpt-5.1',
  inputProcessors: [
    new MessageLengthLimiter(500), // 500 character limit
  ],
});

const shortMessage = 'What is the capital of France?'; // 31 characters

const result = await agent.generate(shortMessage);
console.log(result.text);
```

### High example output

The message processes successfully because it's well under the 500-character limit:

```typescript
"The capital of France is Paris. It's located in the north-central part of the country...";
```

## Partial example (approaching limits)

This example shows a message that's close to but still within the character limit.

```typescript title="src/example-partial-message-length.ts" showLineNumbers copy
import { Agent } from '@mastra/core/agent';
import { MessageLengthLimiter } from './mastra/processors/message-length-limiter';

// Reuse same agent but with tighter character limit
export const agent = new Agent({
  id: 'length-limited-agent',
  name: 'Length Limited Agent',
  instructions: 'You are a helpful assistant',
  model: 'openai/gpt-5.1',
  inputProcessors: [
    new MessageLengthLimiter(300), // 300 character limit
  ],
});

const mediumMessage =
  "Can you explain the difference between machine learning and artificial intelligence? I'm particularly interested in understanding how they relate to each other and what makes them distinct in the field of computer science."; // ~250 characters

const result = await agent.generate(mediumMessage);
console.log(result.text);
```

### Partial example output

The message processes successfully as it's under the 300-character limit:

```typescript
'Machine learning is a subset of artificial intelligence. AI is the broader concept of machines performing tasks in a smart way...';
```

## Low example (exceeds limits)

This example shows what happens when a message exceeds the configured character limit.

```typescript title="src/example-low-message-length.ts" showLineNumbers copy
import { Agent } from '@mastra/core/agent';
import { MessageLengthLimiter } from './mastra/processors/message-length-limiter';

// Reuse same agent but with very strict character limit
export const agent = new Agent({
  id: 'length-limited-agent',
  name: 'Length Limited Agent',
  instructions: 'You are a helpful assistant',
  model: 'openai/gpt-5.1',
  inputProcessors: [
    new MessageLengthLimiter(100), // Very strict 100 character limit
  ],
});

const longMessage =
  'I need you to provide a comprehensive analysis of the economic implications of artificial intelligence on global markets, including detailed examination of how AI adoption affects employment rates, productivity metrics, consumer behavior patterns, and long-term economic forecasting models that governments and corporations use for strategic planning purposes.'; // ~400+ characters

const result = await agent.generate(longMessage);

if (result.tripwire) {
  console.log('Request blocked:', result.tripwire.reason);
} else {
  console.log(result.text);
}
```

### Low example output

The request is blocked because the message exceeds the 100-character limit:

```typescript
Request blocked: Message too long: 412 characters (max: 100)
```

## Understanding the results

When using `MessageLengthLimiter`, the processor:

### Successful processing

- **Within limits**: Messages under the character limit process normally
- **Character counting**: Only counts text content from message parts
- **Multi-message support**: Counts total length across all messages in the thread

### Blocked processing

- **Exceeded limits**: Messages over the limit set `result.tripwire = true`
- **Error details**: `result.tripwire.reason` includes actual length and configured maximum
- **Immediate blocking**: Processing stops before reaching the language model
- **No exceptions**: Check `result.tripwire` instead of using try/catch blocks

### Configuration options

- **maxLength**: Set the character limit (default: 1000)
- **Custom limits**: Different agents can have different length requirements
- **Runtime overrides**: Can be overridden per-call if needed

### Best practices

- Set realistic limits based on your model's context window
- Consider the cumulative length of conversation history
- Use shorter limits for cost-sensitive applications
- Implement user feedback for blocked messages in production

This processor is particularly useful for:

- Controlling API costs by preventing oversized requests
- Ensuring consistent input validation across your application
- Protecting against accidentally large inputs that could cause timeouts
- Implementing tiered access controls based on user permissions
