elizaOS

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

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:

  1. Clarity: Use clear, specific instructions
  2. Structure: Maintain consistent XML structure
  3. Flexibility: Design for multiple platforms
  4. Performance: Optimize for fast processing
  5. 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>
  `;
}

Next Steps