> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abv.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Message Placeholders in Chat Prompts

> Dynamically inject message arrays (chat history, few-shot examples, RAG context) into prompt templates at runtime for flexible conversation management.

# How Message Placeholders Work

<Steps>
  <Step title="Define placeholder in prompt template" icon="plus-circle">
    Create a chat prompt and insert a message placeholder at the desired position. The placeholder is a special message object with `type: "placeholder"` and a `name` you'll reference at runtime.

    ```python theme={null}
    prompt=[
      {"role": "system", "content": "You are an {{criticlevel}} movie critic"},
      {"type": "placeholder", "name": "chat_history"},  # Placeholder
      {"role": "user", "content": "What should I watch next?"}
    ]
    ```

    The placeholder sits between the system message and final user message, ready to accept chat history at runtime.
  </Step>

  <Step title="Fetch prompt at runtime" icon="cloud-arrow-down">
    In your application, fetch the prompt using the ABV SDK. The SDK retrieves the template with placeholders intact, ready for compilation.

    ```python theme={null}
    from abvdev import ABV

    abv = ABV(api_key="sk-abv-...")
    prompt = abv.get_prompt("movie-critic-chat")
    ```

    The fetched prompt contains the template structure, including all placeholders and variables.
  </Step>

  <Step title="Compile with message arrays" icon="code-merge">
    Use the `.compile(variables, placeholders)` method to resolve both template variables and message placeholders. Pass a dictionary mapping placeholder names to message arrays.

    ```python theme={null}
    compiled_prompt = prompt.compile(
        criticlevel="expert",  # Resolve variable
        chat_history=[         # Resolve placeholder
            {"role": "user", "content": "I love Ron Fricke movies like Baraka"},
            {"role": "assistant", "content": "Baraka is a masterpiece of visual storytelling."},
            {"role": "user", "content": "Also, Memories of a Murderer"}
        ]
    )
    ```

    The SDK injects the `chat_history` array at the placeholder's position while resolving the `{{criticlevel}}` variable.
  </Step>

  <Step title="Send compiled messages to LLM" icon="paper-plane">
    The compiled result is a complete message array ready for the LLM API. ABV handles ordering, role consistency, and variable interpolation automatically.

    ```python theme={null}
    # compiled_prompt = [
    #   {"role": "system", "content": "You are an expert movie critic"},
    #   {"role": "user", "content": "I love Ron Fricke movies like Baraka"},
    #   {"role": "assistant", "content": "Baraka is a masterpiece..."},
    #   {"role": "user", "content": "Also, Memories of a Murderer"},
    #   {"role": "user", "content": "What should I watch next?"}
    # ]

    response = openai_client.chat.completions.create(
        model="gpt-4o",
        messages=compiled_prompt
    )
    ```
  </Step>
</Steps>

# Best Practices

<AccordionGroup>
  <Accordion title="Use Descriptive Placeholder Names" icon="tag">
    Name placeholders based on their semantic purpose, not their position.

    **Good:**

    ```python theme={null}
    {"type": "placeholder", "name": "chat_history"}
    {"type": "placeholder", "name": "few_shot_examples"}
    {"type": "placeholder", "name": "retrieved_documents"}
    ```

    **Avoid:**

    ```python theme={null}
    {"type": "placeholder", "name": "placeholder1"}
    {"type": "placeholder", "name": "messages"}
    {"type": "placeholder", "name": "data"}
    ```

    Clear names make templates self-documenting and prevent compilation errors.
  </Accordion>

  <Accordion title="Validate Message Arrays Before Compilation" icon="circle-check">
    Ensure message arrays passed to placeholders have valid structure (role, content fields) to avoid LLM API errors.

    ```python theme={null}
    def validate_messages(messages):
        for msg in messages:
            assert "role" in msg, f"Message missing 'role': {msg}"
            assert "content" in msg, f"Message missing 'content': {msg}"
            assert msg["role"] in ["system", "user", "assistant"], f"Invalid role: {msg['role']}"
        return messages

    # Use before compilation
    compiled = prompt.compile(
        chat_history=validate_messages(conversation_history)
    )
    ```

    This catches errors early rather than failing at the LLM API call.
  </Accordion>

  <Accordion title="Order Placeholders Thoughtfully" icon="arrow-down-1-9">
    Place placeholders in the message sequence that matches conversation flow: system context → examples → history → current input.

    ```python theme={null}
    [
      {"role": "system", "content": "You are a helpful assistant"},
      {"type": "placeholder", "name": "few_shot_examples"},      # First: examples
      {"type": "placeholder", "name": "conversation_history"},   # Then: history
      {"role": "user", "content": "{{current_question}}"}        # Finally: current input
    ]
    ```

    This order matches how conversations naturally unfold and how LLMs process context.
  </Accordion>

  <Accordion title="Combine Variables and Placeholders" icon="code-merge">
    Use template variables for simple string substitution and message placeholders for dynamic message arrays.

    ```python theme={null}
    [
      {"role": "system", "content": "You are a {{role}} for {{company}}"},  # Variables
      {"type": "placeholder", "name": "context"},                           # Placeholder
      {"role": "user", "content": "{{question}}"}                           # Variable
    ]
    ```

    **Compilation:**

    ```python theme={null}
    compiled = prompt.compile(
        role="customer support agent",        # Variable
        company="Acme Corp",                  # Variable
        question="How do I return an item?",  # Variable
        context=[                             # Placeholder
            {"role": "system", "content": "Return policy: 30 days"},
            {"role": "system", "content": "Restocking fee: 15%"}
        ]
    )
    ```

    This combination provides maximum flexibility for both static and dynamic content.
  </Accordion>

  <Accordion title="Handle Empty Placeholders Gracefully" icon="circle-minus">
    Design your application to handle cases where placeholder arrays might be empty (e.g., first message in a conversation has no history).

    ```python theme={null}
    # Fetch prompt
    prompt = abv.get_prompt("customer-support-chat")

    # Handle empty chat history (first message)
    chat_history = get_conversation_history(user_id)  # Might return []

    compiled = prompt.compile(
        current_question=user_question,
        conversation_history=chat_history  # Can be empty list
    )
    ```

    ABV handles empty arrays gracefully—the placeholder simply doesn't insert any messages. Your prompt template works for both first messages and ongoing conversations.
  </Accordion>
</AccordionGroup>

# Implementation Examples

<AccordionGroup>
  <Accordion title="Create Prompt with Placeholders via UI" icon="browser">
    <img src="https://mintlify.s3.us-west-1.amazonaws.com/abv-2be93c70/images/prompt-management-message-placeholders-1d9343d4.png" alt="Message placeholder UI" />

    1. Navigate to Prompt Management in ABV dashboard
    2. Create a new chat prompt or edit an existing one
    3. Click **Add message placeholder** button
    4. Enter a descriptive `name` (e.g., `chat_history`, `examples`)
    5. Position the placeholder in your message sequence
    6. Save the prompt

    The placeholder appears as a distinct message type in the prompt editor.
  </Accordion>

  <Accordion title="Create Prompt with Placeholders via Python SDK" icon="python">
    **Install ABV SDK:**

    ```bash theme={null}
    pip install abvdev
    ```

    **Create prompt with message placeholder:**

    ```python theme={null}
    from abvdev import ABV

    # Initialize ABV client
    abv = ABV(
        api_key="sk-abv-...",
        host="https://app.abv.dev"  # or "https://eu.app.abv.dev" for EU region
    )

    # Create prompt with placeholder
    abv.create_prompt(
        name="movie-critic-chat",
        type="chat",
        prompt=[
            {"role": "system", "content": "You are an {{criticlevel}} movie critic"},
            {"type": "placeholder", "name": "chat_history"},
            {"role": "user", "content": "What should I watch next?"}
        ],
        labels=["production"]
    )
    ```

    **Fetch and compile at runtime:**

    ```python theme={null}
    # Fetch prompt
    prompt = abv.get_prompt("movie-critic-chat")

    # Compile with variable and placeholder
    compiled_prompt = prompt.compile(
        criticlevel="expert",
        chat_history=[
            {"role": "user", "content": "I love Ron Fricke movies like Baraka"},
            {"role": "assistant", "content": "Baraka is a visual masterpiece."},
            {"role": "user", "content": "Also, Memories of a Murderer"}
        ]
    )

    # Result:
    # [
    #   {"role": "system", "content": "You are an expert movie critic"},
    #   {"role": "user", "content": "I love Ron Fricke movies like Baraka"},
    #   {"role": "assistant", "content": "Baraka is a visual masterpiece."},
    #   {"role": "user", "content": "Also, Memories of a Murderer"},
    #   {"role": "user", "content": "What should I watch next?"}
    # ]
    ```
  </Accordion>

  <Accordion title="Create Prompt with Placeholders via JavaScript/TypeScript SDK" icon="js">
    **Install ABV SDK:**

    ```bash theme={null}
    npm install @abvdev/client
    ```

    **Set up environment variables:**

    ```bash theme={null}
    npm install dotenv
    ```

    **Create `.env` file:**

    ```bash title=".env" theme={null}
    ABV_API_KEY=sk-abv-...
    ABV_BASEURL=https://app.abv.dev  # or https://eu.app.abv.dev for EU region
    ```

    **Create prompt with placeholder:**

    ```typescript theme={null}
    import { ABVClient } from "@abvdev/client";
    import dotenv from "dotenv";
    dotenv.config();

    const abv = new ABVClient();

    async function createPrompt() {
        await abv.prompt.create({
            name: "movie-critic-chat",
            type: "chat",
            prompt: [
                { role: "system", content: "You are an {{criticlevel}} movie critic" },
                { type: "placeholder", name: "chat_history" },
                { role: "user", content: "What should I watch next?" }
            ],
            labels: ["production"]
        });
    }

    createPrompt();
    ```

    **Fetch and compile at runtime:**

    ```typescript theme={null}
    async function usePrompt() {
        const prompt = await abv.prompt.get("movie-critic-chat", { type: "chat" });

        const compiledPrompt = prompt.compile(
            // Variables
            { criticlevel: "expert" },
            // Placeholders
            {
                chat_history: [
                    { role: "user", content: "I love Ron Fricke movies like Baraka" },
                    { role: "assistant", content: "Baraka is a visual masterpiece." },
                    { role: "user", content: "Also, Memories of a Murderer" }
                ]
            }
        );

        console.log(compiledPrompt);
        // [
        //   { role: "system", content: "You are an expert movie critic" },
        //   { role: "user", content: "I love Ron Fricke movies like Baraka" },
        //   { role: "assistant", content: "Baraka is a visual masterpiece." },
        //   { role: "user", content: "Also, Memories of a Murderer" },
        //   { role: "user", content: "What should I watch next?" }
        // ]
    }

    usePrompt();
    ```

    **Alternative: Constructor parameters instead of environment variables:**

    ```typescript theme={null}
    const abv = new ABVClient({
        apiKey: "sk-abv-...",
        baseUrl: "https://app.abv.dev"
    });
    ```
  </Accordion>
</AccordionGroup>

# Next Steps

<CardGroup cols={2}>
  <Card title="Get Started with Prompt Management" icon="rocket" href="/developer/prompt-management/get-started">
    Complete quickstart guide for creating, versioning, and deploying prompts
  </Card>

  <Card title="Prompt Data Model" icon="database" href="/developer/prompt-management/prompts-data-model">
    Deep dive into prompt structure, fields, and versioning
  </Card>

  <Card title="Version Control" icon="code-branch" href="/developer/prompt-management/version-control">
    Deploy and rollback prompts safely using labels and versions
  </Card>

  <Card title="Prompt Composability" icon="puzzle-piece" href="/developer/prompt-management/composability">
    Build complex prompts by composing reusable prompt components
  </Card>
</CardGroup>
