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.
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.
Fetch prompt at runtime
In your application, fetch the prompt using the ABV SDK. The SDK retrieves the template with placeholders intact, ready for compilation.
from abvdev import ABVabv = ABV(api_key="sk-abv-...")prompt = abv.get_prompt("movie-critic-chat")
The fetched prompt contains the template structure, including all placeholders and variables.
Compile with message arrays
Use the .compile(variables, placeholders) method to resolve both template variables and message placeholders. Pass a dictionary mapping placeholder names to message arrays.
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.
Send compiled messages to LLM
The compiled result is a complete message array ready for the LLM API. ABV handles ordering, role consistency, and variable interpolation automatically.
# 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)
Clear names make templates self-documenting and prevent compilation errors.
Validate Message Arrays Before Compilation
Ensure message arrays passed to placeholders have valid structure (role, content fields) to avoid LLM API errors.
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 compilationcompiled = prompt.compile( chat_history=validate_messages(conversation_history))
This catches errors early rather than failing at the LLM API call.
Order Placeholders Thoughtfully
Place placeholders in the message sequence that matches conversation flow: system context → examples → history → current input.
[ {"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.
Combine Variables and Placeholders
Use template variables for simple string substitution and message placeholders for dynamic message arrays.
[ {"role": "system", "content": "You are a {{role}} for {{company}}"}, # Variables {"type": "placeholder", "name": "context"}, # Placeholder {"role": "user", "content": "{{question}}"} # Variable]
Compilation:
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.
Handle Empty Placeholders Gracefully
Design your application to handle cases where placeholder arrays might be empty (e.g., first message in a conversation has no history).
# Fetch promptprompt = 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.
Enter a descriptive name (e.g., chat_history, examples)
Position the placeholder in your message sequence
Save the prompt
The placeholder appears as a distinct message type in the prompt editor.
Create Prompt with Placeholders via Python SDK
Install ABV SDK:
pip install abvdev
Create prompt with message placeholder:
from abvdev import ABV# Initialize ABV clientabv = ABV( api_key="sk-abv-...", host="https://app.abv.dev" # or "https://eu.app.abv.dev" for EU region)# Create prompt with placeholderabv.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:
# Fetch promptprompt = abv.get_prompt("movie-critic-chat")# Compile with variable and placeholdercompiled_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?"}# ]
Create Prompt with Placeholders via JavaScript/TypeScript SDK
Install ABV SDK:
npm install @abvdev/client
Set up environment variables:
npm install dotenv
Create .env file:
.env
ABV_API_KEY=sk-abv-...ABV_BASEURL=https://app.abv.dev # or https://eu.app.abv.dev for EU region
Create prompt with placeholder:
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:
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:
const abv = new ABVClient({ apiKey: "sk-abv-...", baseUrl: "https://app.abv.dev"});