Prompt Templates Customization Guide
Complete guide to customizing prompt templates for all message handlers in ElizaOS, including examples for different client types and use cases
Learn how to customize prompt templates for all ElizaOS message handlers to create specialized agent behaviors across all client types - REST API, Discord, Twitter, Telegram, and more.
Universal Processing: All prompt templates work identically across all client types. Whether messages come from Discord, Twitter, REST API, or any other platform, the same templates and handlers process them through the unified message processing pipeline.
Template System Overview
ElizaOS uses a sophisticated template system that controls how agents process and respond to messages. The core templates are:
Core Message Processing Templates
shouldRespondTemplate - Decision Making
Controls whether the agent should respond to incoming messages:
export const shouldRespondTemplate = `<task>Decide on behalf of {{agentName}} whether they should respond to the message, ignore it or stop the conversation.</task>
<providers>
{{providers}}
</providers>
<instructions>Decide if {{agentName}} should respond to or interact with the conversation.
If the message is directed at or relevant to {{agentName}}, respond with RESPOND action.
If a user asks {{agentName}} to be quiet, respond with STOP action.
If {{agentName}} should ignore the message, respond with IGNORE action.</instructions>
<output>
Do NOT include any thinking, reasoning, or <think> sections in your response.
Go directly to the XML response format without any preamble or explanation.
Respond using XML format like this:
<response>
<name>{{agentName}}</name>
<reasoning>Your reasoning here</reasoning>
<action>RESPOND | IGNORE | STOP</action>
</response>
IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.
</output>`;
messageHandlerTemplate - Response Generation
Generates the agent's response content and determines actions:
export const messageHandlerTemplate = `<task>Generate dialog and actions for the character {{agentName}}.</task>
<providers>
{{providers}}
</providers>
These are the available valid actions:
<actionNames>
{{actionNames}}
</actionNames>
<instructions>
Write a thought and plan for {{agentName}} and decide what actions to take. Also include the providers that {{agentName}} will use to have the right context for responding and acting, if any.
IMPORTANT ACTION ORDERING RULES:
- Actions are executed in the ORDER you list them - the order MATTERS!
- REPLY should come FIRST to acknowledge the user's request before executing other actions
- Common patterns:
- For requests requiring tool use: REPLY,CALL_MCP_TOOL (acknowledge first, then gather info)
- For task execution: REPLY,SEND_MESSAGE or REPLY,EVM_SWAP_TOKENS (acknowledge first, then do the task)
- For multi-step operations: REPLY,ACTION1,ACTION2 (acknowledge first, then complete all steps)
- REPLY is used to acknowledge and inform the user about what you're going to do
- Follow-up actions execute the actual tasks after acknowledgment
- Use IGNORE only when you should not respond at all
IMPORTANT PROVIDER SELECTION RULES:
- If the message mentions images, photos, pictures, attachments, or visual content, OR if you see "(Attachments:" in the conversation, you MUST include "ATTACHMENTS" in your providers list
- If the message asks about or references specific people, include "ENTITIES" in your providers list
- If the message asks about relationships or connections between people, include "RELATIONSHIPS" in your providers list
- If the message asks about facts or specific information, include "FACTS" in your providers list
- If the message asks about the environment or world context, include "WORLD" in your providers list
- If you need external knowledge, information, or context beyond the current conversation to provide a helpful response, include "KNOWLEDGE" in your providers list
First, think about what you want to do next and plan your actions. Then, write the next message and include the actions you plan to take.
</instructions>
<keys>
"thought" should be a short description of what the agent is thinking about and planning.
"actions" should be a comma-separated list of the actions {{agentName}} plans to take based on the thought, IN THE ORDER THEY SHOULD BE EXECUTED (if none, use IGNORE, if simply responding with text, use REPLY)
"providers" should be a comma-separated list of the providers that {{agentName}} will use to have the right context for responding and acting (NEVER use "IGNORE" as a provider - use specific provider names like ATTACHMENTS, ENTITIES, FACTS, KNOWLEDGE, etc.)
"text" should be the text of the next message for {{agentName}} which they will send to the conversation.
</keys>
<output>
Do NOT include any thinking, reasoning, or <think> sections in your response.
Go directly to the XML response format without any preamble or explanation.
Respond using XML format like this:
<response>
<thought>Your thought here</thought>
<actions>ACTION1,ACTION2</actions>
<providers>PROVIDER1,PROVIDER2</providers>
<text>Your response text here</text>
</response>
IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.
</output>`;
postCreationTemplate - Content Creation
For creating social media posts or proactive content:
export const postCreationTemplate = `# Task: Create a post in the voice and style and perspective of {{agentName}} @{{twitterUserName}}.
Example task outputs:
1. A post about the importance of AI in our lives
<response>
<thought>I am thinking about writing a post about the importance of AI in our lives</thought>
<post>AI is changing the world and it is important to understand how it works</post>
<imagePrompt>A futuristic cityscape with flying cars and people using AI to do things</imagePrompt>
</response>
2. A post about dogs
<response>
<thought>I am thinking about writing a post about dogs</thought>
<post>Dogs are man's best friend and they are loyal and loving</post>
<imagePrompt>A dog playing with a ball in a park</imagePrompt>
</response>
3. A post about finding a new job
<response>
<thought>Getting a job is hard, I bet there's a good tweet in that</thought>
<post>Just keep going!</post>
<imagePrompt>A person looking at a computer screen with a job search website</imagePrompt>
</response>
{{providers}}
Write a post that is {{adjective}} about {{topic}} (without mentioning {{topic}} directly), from the perspective of {{agentName}}. Do not add commentary or acknowledge this request, just write the post.
Your response should be 1, 2, or 3 sentences (choose the length at random).
Your response should not contain any questions. Brief, concise statements only. The total character count MUST be less than 280. No emojis. Use \n\n (double spaces) between statements if there are multiple statements in your response.
Your output should be formatted in XML like this:
<response>
<thought>Your thought here</thought>
<post>Your post text here</post>
<imagePrompt>Optional image prompt here</imagePrompt>
</response>
The "post" field should be the post you want to send. Do not including any thinking or internal reflection in the "post" field.
The "imagePrompt" field is optional and should be a prompt for an image that is relevant to the post. It should be a single sentence that captures the essence of the post. ONLY USE THIS FIELD if it makes sense that the post would benefit from an image.
The "thought" field should be a short description of what the agent is thinking about before responding, inlcuding a brief justification for the response. Includate an explanation how the post is relevant to the topic but unique and different than other posts.
Do NOT include any thinking, reasoning, or <think> sections in your response.
Go directly to the XML response format without any preamble or explanation.
IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.`;
imageDescriptionTemplate - Image Analysis
For analyzing and describing images in attachments:
export const imageDescriptionTemplate = `<task>Analyze the provided image and generate a comprehensive description with multiple levels of detail.</task>
<instructions>
Carefully examine the image and provide:
1. A concise, descriptive title that captures the main subject or scene
2. A brief summary description (1-2 sentences) highlighting the key elements
3. An extensive, detailed description that covers all visible elements, composition, lighting, colors, mood, and any other relevant details
Be objective and descriptive. Focus on what you can actually see in the image rather than making assumptions about context or meaning.
</instructions>
<output>
Do NOT include any thinking, reasoning, or <think> sections in your response.
Go directly to the XML response format without any preamble or explanation.
Respond using XML format like this:
<response>
<title>A concise, descriptive title for the image</title>
<description>A brief 1-2 sentence summary of the key elements in the image</description>
<text>An extensive, detailed description covering all visible elements, composition, lighting, colors, mood, setting, objects, people, activities, and any other relevant details you can observe in the image</text>
</response>
IMPORTANT: Your response must ONLY contain the <response></response> XML block above. Do not include any text, thinking, or reasoning before or after this XML block. Start your response immediately with <response> and end with </response>.
</output>`;
Platform-Specific Template Customization
REST API Optimized Templates
For REST API interactions, optimize templates for structured data exchange:
const apiOptimizedTemplate = `<task>
Generate a structured response for {{agentName}} to API request.
</task>
<providers>
{{providers}}
</providers>
<requestContext>
- Platform: REST API
- Endpoint: {{endpoint}}
- Method: {{method}}
- User Agent: {{userAgent}}
</requestContext>
<instructions>
As {{agentName}}, provide a structured response for the API request.
API Response Guidelines:
- Be concise but complete
- Include relevant data points
- Use consistent formatting
- Provide actionable information
- Reference request context when relevant
Response Structure:
- Clear acknowledgment
- Relevant information
- Next steps if applicable
- Error handling if needed
</instructions>
<output>
<response>
<thought>API request analysis and response strategy</thought>
<actions>REPLY</actions>
<providers>KNOWLEDGE,FACTS</providers>
<text>Structured response for API consumer</text>
<metadata>
<responseType>api_response</responseType>
<confidence>{{confidence}}</confidence>
<sources>{{sources}}</sources>
</metadata>
</response>
</output>`;
Discord-Optimized Templates
For Discord interactions, customize for community engagement:
const discordOptimizedTemplate = `<task>
Generate a Discord message response for {{agentName}}.
</task>
<providers>
{{providers}}
</providers>
<discordContext>
- Server: {{serverName}}
- Channel: {{channelName}}
- Message Type: {{messageType}}
- Mentions: {{mentions}}
- Thread: {{threadInfo}}
</discordContext>
<instructions>
As {{agentName}}, engage with the Discord community.
Discord Guidelines:
- Use Discord markdown (**, *, \`\`\`, etc.)
- Reference users with @mentions when appropriate
- Keep responses conversational and community-focused
- Use emojis sparingly and appropriately
- Consider server context and channel purpose
Response Style:
- Friendly and approachable
- Community-oriented
- Contextually aware
- Engaging and interactive
</instructions>
<output>
<response>
<thought>Discord community engagement strategy</thought>
<actions>REPLY</actions>
<providers>KNOWLEDGE,ENTITIES</providers>
<text>Discord-formatted response with markdown</text>
<reactions>👍,✨,🤖</reactions>
</response>
</output>`;
Twitter-Optimized Templates
For Twitter interactions, focus on concise, engaging content:
const twitterOptimizedTemplate = `<task>
Generate a Twitter response for {{agentName}}.
</task>
<providers>
{{providers}}
</providers>
<twitterContext>
- Tweet Type: {{tweetType}}
- In Reply To: {{inReplyTo}}
- Mentions: {{mentions}}
- Hashtags: {{hashtags}}
- Character Limit: 280
</twitterContext>
<instructions>
As {{agentName}}, create a Twitter-appropriate response.
Twitter Guidelines:
- Maximum 280 characters
- Use relevant hashtags (#)
- Include @mentions when replying
- Be concise but engaging
- Consider viral potential
- Use Twitter-friendly formatting
Tone Considerations:
- Conversational and accessible
- Personality-driven
- Topical and timely
- Engaging and shareable
</instructions>
<output>
<response>
<thought>Twitter engagement strategy</thought>
<actions>REPLY</actions>
<providers>KNOWLEDGE</providers>
<text>Concise Twitter response under 280 characters</text>
<hashtags>#relevant #hashtags</hashtags>
<mentions>@relevantUsers</mentions>
</response>
</output>`;
Other Core Templates
Boolean Footer Template
Used for simple yes/no decision prompts:
export const booleanFooter = 'Respond with only a YES or a NO.';
Template Composition Functions
composePromptFromState
This utility function combines state values with templates:
import { composePromptFromState } from '@elizaos/core';
// Basic usage
const prompt = composePromptFromState({
state,
template: messageHandlerTemplate,
});
// The function replaces template variables with state values:
// {{agentName}} -> state.values.agentName
// {{providers}} -> state.text (formatted provider data)
// {{recentMessages}} -> state.values.recentMessages
// {{actionNames}} -> state.values.actionNames
// {{topic}} -> state.values.topic
// {{adjective}} -> state.values.adjective
// And any other values in state.values
Character-Specific Template Customization
You can override default templates by adding them to your character definition:
// character.json
{
"name": "TechSupport",
"bio": ["I'm a technical support specialist helping users with software and hardware issues"],
"templates": {
"shouldRespondTemplate": "<custom should respond template>",
"messageHandlerTemplate": "<custom message handler template>",
"postCreationTemplate": "<custom post creation template>"
}
}
Technical Support Agent Example
{
"name": "TechSupport",
"bio": ["I'm a technical support specialist helping users with software and hardware issues"],
"templates": {
"messageHandlerTemplate": "<task>\nProvide technical support as {{agentName}}.\n</task>
<providers>
{{providers}}
</providers>
<supportContext>
{{recentMessages}}
</supportContext>
<instructions>
As {{agentName}}, provide technical support following these steps:
1. ACKNOWLEDGE the user's issue
2. ANALYZE the problem description
3. ASK clarifying questions if needed
4. PROVIDE step-by-step solution
5. OFFER follow-up assistance
Technical Support Guidelines:
- Be patient and understanding
- Use clear, non-technical language
- Provide specific, actionable steps
- Offer multiple solutions when possible
- Escalate complex issues appropriately
Response Structure:
- Problem acknowledgment
- Diagnosis or clarification
- Solution steps
- Verification request
</instructions>
<output>
<response>
<thought>Technical analysis and support strategy</thought>
<actions>REPLY</actions>
<providers>KNOWLEDGE,FACTS</providers>
<text>Technical support response with clear steps</text>
<troubleshooting>
<diagnosis>Problem analysis</diagnosis>
<steps>Solution steps</steps>
<verification>How to verify fix</verification>
</troubleshooting>
</response>
</output>`
}
}
Custom Template in Character Definition
Templates can be embedded directly in your character configuration:
// In your character definition file
export const myCharacter = {
name: "MyAgent",
bio: ["I am a specialized agent"],
templates: {
// Override the message handler template
messageHandlerTemplate: `<task>Generate specialized response for {{agentName}}.</task>
<providers>
{{providers}}
</providers>
<instructions>
Specialized instructions for my agent...
</instructions>
<output>
<response>
<thought>{{agentName}}'s analysis</thought>
<actions>REPLY</actions>
<providers>KNOWLEDGE</providers>
<text>Specialized response</text>
</response>
</output>`,
// Override should respond template
shouldRespondTemplate: `<task>Custom decision logic for {{agentName}}</task>
<!-- Custom template content -->`,
// Override post creation template
postCreationTemplate: `<task>Create specialized content for {{agentName}}</task>
<!-- Custom template content -->`
}
};
Sales Assistant Example
{
"name": "SalesBot",
"bio": ["I'm a sales assistant helping customers find the right products"],
"templates": {
"messageHandlerTemplate": "<task>\nProvide sales assistance as {{agentName}}.\n</task>
<providers>
{{providers}}
</providers>
<salesContext>
- Customer: {{customerName}}
- Previous Interactions: {{recentMessages}}
- Current Products: {{availableProducts}}
- Customer Preferences: {{customerPreferences}}
</salesContext>
<instructions>
As {{agentName}}, guide customers through the sales process:
SALES METHODOLOGY:
1. DISCOVER customer needs
2. PRESENT relevant solutions
3. HANDLE objections professionally
4. CLOSE with clear next steps
Sales Guidelines:
- Be helpful, not pushy
- Focus on customer value
- Provide detailed product information
- Offer comparisons when helpful
- Create urgency appropriately
Response Style:
- Professional and friendly
- Solution-oriented
- Value-focused
- Consultative approach
</instructions>
<output>
<response>
<thought>Sales strategy and customer needs analysis</thought>
<actions>REPLY</actions>
<providers>KNOWLEDGE,PRODUCTS</providers>
<text>Sales-focused response with product recommendations</text>
<products>
<recommended>Product recommendations</recommended>
<alternatives>Alternative options</alternatives>
</products>
<nextSteps>Clear next steps for customer</nextSteps>
</response>
</output>"
}
}
Runtime Template Access
Templates are accessed through the runtime's character object:
// In an action or provider
const template = runtime.character.templates?.messageHandlerTemplate
|| messageHandlerTemplate; // fallback to default
const prompt = composePromptFromState({
state,
template
});
Creative Writing Assistant
{
"name": "CreativeWriter",
"bio": ["I'm a creative writing assistant helping with stories, poems, and creative content"],
"templates": {
"messageHandlerTemplate": `<task>
Provide creative writing assistance as {{agentName}}.
</task>
<providers>
{{providers}}
</providers>
<creativeContext>
- Writing Project: {{projectType}}
- Genre: {{genre}}
- Style: {{writingStyle}}
- Audience: {{targetAudience}}
- Previous Work: {{recentMessages}}
</creativeContext>
<instructions>
As {{agentName}}, help with creative writing by:
CREATIVE PROCESS:
1. UNDERSTAND the creative vision
2. BRAINSTORM ideas and concepts
3. DEVELOP characters, plot, or themes
4. REFINE and polish content
5. PROVIDE constructive feedback
Creative Guidelines:
- Encourage experimentation
- Provide specific, actionable feedback
- Offer multiple creative options
- Balance creativity with structure
- Inspire and motivate
Response Approach:
- Enthusiastic and supportive
- Detail-oriented
- Imaginative and inspiring
- Technically skilled
</instructions>
<output>
<response>
<thought>Creative analysis and writing strategy</thought>
<actions>REPLY</actions>
<providers>KNOWLEDGE,CREATIVE</providers>
<text>Creative writing guidance and suggestions</text>
<techniques>
<suggested>Writing techniques to try</suggested>
<examples>Specific examples or prompts</examples>
</techniques>
<inspiration>Creative inspiration or direction</inspiration>
</response>
</output>`
}
}
Advanced Template Features
Dynamic Template Selection
export function selectTemplateForContext(
message: Memory,
runtime: IAgentRuntime
): string {
const messageText = message.content.text?.toLowerCase() || '';
const source = message.content.source;
// Platform-specific templates
if (source === 'discord') {
return runtime.character.templates?.discordTemplate || discordOptimizedTemplate;
}
if (source === 'twitter') {
return runtime.character.templates?.twitterTemplate || twitterOptimizedTemplate;
}
if (source === 'api' || source === 'rest_api') {
return runtime.character.templates?.apiTemplate || apiOptimizedTemplate;
}
// Content-specific templates
if (messageText.includes('support') || messageText.includes('help')) {
return runtime.character.templates?.supportTemplate || supportHandlerTemplate;
}
if (messageText.includes('buy') || messageText.includes('price')) {
return runtime.character.templates?.salesTemplate || salesHandlerTemplate;
}
if (messageText.includes('write') || messageText.includes('story')) {
return runtime.character.templates?.creativeTemplate || creativeHandlerTemplate;
}
// Default template
return runtime.character.templates?.messageHandlerTemplate || messageHandlerTemplate;
}
Template Inheritance
export function createInheritedTemplate(
baseTemplate: string,
customizations: Record<string, string>
): string {
let template = baseTemplate;
// Replace specific sections
Object.entries(customizations).forEach(([section, replacement]) => {
const sectionRegex = new RegExp(`<${section}>[\\s\\S]*?</${section}>`, 'g');
template = template.replace(sectionRegex, `<${section}>\n${replacement}\n</${section}>`);
});
return template;
}
// Usage
const customSupportTemplate = createInheritedTemplate(messageHandlerTemplate, {
instructions: `
As a technical support agent:
1. Acknowledge the technical issue
2. Gather diagnostic information
3. Provide step-by-step troubleshooting
4. Verify the solution works
5. Document the resolution
`
});
Context-Aware Variables
export function injectContextVariables(
template: string,
context: {
message: Memory;
runtime: IAgentRuntime;
additionalContext?: Record<string, any>;
}
): string {
const variables = {
// Standard variables
agentName: context.runtime.character.name,
bio: context.runtime.character.bio?.join(' ') || '',
// Context-specific variables
platform: context.message.content.source || 'unknown',
userAgent: context.message.content.metadata?.userAgent || 'unknown',
timestamp: new Date().toISOString(),
// Message context
hasAttachments: context.message.content.attachments?.length > 0,
mentionsAgent: context.message.content.text?.includes(context.runtime.character.name),
// Additional context
...context.additionalContext
};
return Object.entries(variables).reduce(
(template, [key, value]) =>
template.replace(new RegExp(`{{${key}}}`, 'g'), String(value)),
template
);
}
Template Testing and Validation
Template Validation
export function validateTemplate(template: string): {
isValid: boolean;
errors: string[];
warnings: string[];
} {
const errors: string[] = [];
const warnings: string[] = [];
// Check for required sections
const requiredSections = ['task', 'instructions', 'output'];
requiredSections.forEach(section => {
if (!template.includes(`<${section}>`)) {
errors.push(`Missing required section: ${section}`);
}
});
// Check for output structure
if (!template.includes('<response>')) {
errors.push('Missing response structure in output section');
}
// Check for unclosed tags
const tagRegex = /<(\w+)>/g;
const closingTagRegex = /<\/(\w+)>/g;
const openTags = [...template.matchAll(tagRegex)].map(match => match[1]);
const closeTags = [...template.matchAll(closingTagRegex)].map(match => match[1]);
openTags.forEach(tag => {
if (!closeTags.includes(tag)) {
errors.push(`Unclosed tag: ${tag}`);
}
});
// Check for common variables
const commonVars = ['{{agentName}}', '{{providers}}'];
commonVars.forEach(variable => {
if (!template.includes(variable)) {
warnings.push(`Consider including ${variable} for better context`);
}
});
return {
isValid: errors.length === 0,
errors,
warnings
};
}
Template Testing Framework
export class TemplateTestFramework {
private runtime: IAgentRuntime;
constructor(runtime: IAgentRuntime) {
this.runtime = runtime;
}
async testTemplate(
template: string,
testCases: Array<{
input: string;
expectedActions?: string[];
expectedKeywords?: string[];
platform?: string;
}>
): Promise<Array<{
input: string;
output: any;
passed: boolean;
errors: string[];
}>> {
const results = [];
for (const testCase of testCases) {
try {
const message = this.createTestMessage(testCase.input, testCase.platform);
const state = await this.runtime.composeState(message);
// Apply template
const prompt = this.applyTemplate(template, state);
// Get response
const response = await this.runtime.useModel(ModelType.TEXT_LARGE, {
prompt
});
const parsed = parseKeyValueXml(response);
const errors = this.validateResponse(parsed, testCase);
results.push({
input: testCase.input,
output: parsed,
passed: errors.length === 0,
errors
});
} catch (error) {
results.push({
input: testCase.input,
output: null,
passed: false,
errors: [error.message]
});
}
}
return results;
}
private validateResponse(response: any, testCase: any): string[] {
const errors: string[] = [];
if (testCase.expectedActions) {
const actions = response.actions || [];
testCase.expectedActions.forEach(expectedAction => {
if (!actions.includes(expectedAction)) {
errors.push(`Expected action ${expectedAction} not found`);
}
});
}
if (testCase.expectedKeywords) {
const text = response.text || '';
testCase.expectedKeywords.forEach(keyword => {
if (!text.toLowerCase().includes(keyword.toLowerCase())) {
errors.push(`Expected keyword '${keyword}' not found in response`);
}
});
}
return errors;
}
}
Performance Optimization
Template Caching
class TemplateCache {
private cache = new Map<string, string>();
private compiled = new Map<string, Function>();
get(key: string): string | undefined {
return this.cache.get(key);
}
set(key: string, template: string): void {
this.cache.set(key, template);
// Pre-compile template for faster execution
this.compiled.set(key, this.compile(template));
}
private compile(template: string): Function {
// Create optimized template function
return (variables: Record<string, any>) => {
return Object.entries(variables).reduce(
(result, [key, value]) =>
result.replace(new RegExp(`{{${key}}}`, 'g'), String(value)),
template
);
};
}
execute(key: string, variables: Record<string, any>): string {
const compiled = this.compiled.get(key);
if (!compiled) {
throw new Error(`Template not found: ${key}`);
}
return compiled(variables);
}
}
// Global template cache
export const templateCache = new TemplateCache();
Async Template Processing
export async function processTemplateAsync(
template: string,
context: any,
options: {
streaming?: boolean;
timeout?: number;
retries?: number;
} = {}
): Promise<string | AsyncGenerator<string>> {
const {
streaming = false,
timeout = 30000,
retries = 3
} = options;
const processWithRetry = async (attempt: number): Promise<string> => {
try {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Template processing timeout')), timeout);
});
const processingPromise = context.runtime.useModel(ModelType.TEXT_LARGE, {
prompt: template,
stream: streaming
});
return await Promise.race([processingPromise, timeoutPromise]);
} catch (error) {
if (attempt < retries) {
console.warn(`Template processing failed, retrying (${attempt + 1}/${retries})`);
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
return processWithRetry(attempt + 1);
}
throw error;
}
};
return processWithRetry(0);
}
Best Practices
Template Design Guidelines
Template Design Principles:
- Clarity: Use clear, specific instructions
- Structure: Maintain consistent XML structure
- Flexibility: Design for multiple platforms
- Performance: Optimize for fast processing
- Testing: Validate with diverse inputs
Security Considerations
export function sanitizeTemplateInput(input: string): string {
// Remove potential injection attacks
return input
.replace(/<script[^>]*>.*?<\/script>/gi, '')
.replace(/javascript:/gi, '')
.replace(/on\w+\s*=/gi, '')
.replace(/\{\{[^}]*\}\}/g, match => {
// Only allow whitelisted variables
const allowedVars = ['agentName', 'providers', 'recentMessages'];
const varName = match.slice(2, -2);
return allowedVars.includes(varName) ? match : '';
});
}
Error Recovery
export function createFallbackTemplate(
primaryTemplate: string,
fallbackTemplate: string
): string {
return `
<task>
Try processing with primary template, fall back to secondary if needed.
</task>
<primaryTemplate>
${primaryTemplate}
</primaryTemplate>
<fallbackTemplate>
${fallbackTemplate}
</fallbackTemplate>
<instructions>
Attempt to process using the primary template. If that fails or produces invalid output, use the fallback template instead.
</instructions>
`;
}