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.
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 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 as any).text.length, 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 textPart = part as any;
const partLength = textPart.text.length;
if (currentLength + partLength > maxLength) {
const remainingChars = maxLength - currentLength;
if (remainingChars > 0) {
textPart.text = textPart.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:
import { Agent } from "@mastra/core/agent";
import { MessageLengthLimiter } from "../processors/message-length-limiter";
export const blockingAgent = new Agent({
name: 'blocking-agent',
instructions: 'You are a helpful assistant with input length limits',
model: "openai/gpt-4o",
inputProcessors: [
new MessageLengthLimiter({ maxLength: 2000, strategy: 'block' }),
],
});
Using the simple number approach (defaults to ‘block’ strategy):
import { Agent } from "@mastra/core/agent";
import { MessageLengthLimiter } from "../processors/message-length-limiter";
export const simpleAgent = new Agent({
name: 'simple-agent',
instructions: 'You are a helpful assistant',
model: "openai/gpt-4o",
inputProcessors: [
new MessageLengthLimiter(500),
],
});
High example (within limits)
This example shows a message that stays within the configured character limit and processes successfully.
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({
name: 'length-limited-agent',
instructions: 'You are a helpful assistant',
model: "openai/gpt-4o",
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:
"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.
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({
name: 'length-limited-agent',
instructions: 'You are a helpful assistant',
model: "openai/gpt-4o",
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:
"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.
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({
name: 'length-limited-agent',
instructions: 'You are a helpful assistant',
model: "openai/gpt-4o",
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.tripwireReason);
} else {
console.log(result.text);
}
Low example output
The request is blocked because the message exceeds the 100-character limit:
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.tripwireReason
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