Packer Module API Reference
The Packer module provides specialized packers for composing prompts with automatic refinement and priority-based ordering. Version 0.1.3+ introduces two specialized packers following the Single Responsibility Principle. Version 0.2.1+ adds default refining strategies and removes token budget constraints. Version 0.2.2 removes unused model parameter for API simplification.
MessagesPacker
Optimized for chat completion APIs (OpenAI, Anthropic). Returns List[Dict[str, str]] directly.
prompt_refiner.packer.MessagesPacker
MessagesPacker(
track_tokens=False,
token_counter=None,
system=None,
context=None,
history=None,
query=None,
)
Bases: BasePacker
Packer for chat completion APIs.
Designed for: - OpenAI Chat Completions (gpt-4, gpt-3.5-turbo, etc.) - Anthropic Messages API (claude-3-opus, claude-3-sonnet, etc.) - Any API using ChatML-style message format
Returns: List[Dict[str, str]] with 'role' and 'content' keys
Example
from prompt_refiner import MessagesPacker
Basic usage with automatic refining
packer = MessagesPacker( ... system="You are helpful.", ... context=["
Doc 1", "Doc 2"], ... query="What's the weather?" ... ) messages = packer.pack()Use directly: openai.chat.completions.create(messages=messages)
Traditional API still supported
packer = MessagesPacker() packer.add("System prompt", role="system") packer.add("User query", role="user") messages = packer.pack()
Initialize messages packer.
Default Refining Strategies: When no explicit refiner is provided, automatic refining strategies are applied: - system/query: MinimalStrategy (StripHTML + NormalizeWhitespace) - context/history: StandardStrategy (StripHTML + NormalizeWhitespace + Deduplicate)
To override defaults, provide explicit refiner tuple: (content, refiner). For raw content with no refinement, use .add() method with refine_with=None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
track_tokens
|
bool
|
Enable token tracking to measure refinement effectiveness |
False
|
token_counter
|
Optional[Callable[[str], int]]
|
Function to count tokens (required if track_tokens=True) |
None
|
system
|
Optional[Union[str, Tuple[str, Refiner]]]
|
System message. Can be: - str: "You are helpful" (automatically refined with MinimalStrategy) - Tuple[str, Refiner]: ("You are helpful", StripHTML()) - Tuple[str, Pipeline]: ("You are helpful", StripHTML() | NormalizeWhitespace()) |
None
|
context
|
Optional[Union[List[str], Tuple[List[str], Refiner]]]
|
Context documents. Can be: - List[str]: ["doc1", "doc2"] - Tuple[List[str], Refiner]: (["doc1", "doc2"], StripHTML()) - Tuple[List[str], Pipeline]: (["doc1", "doc2"], StripHTML() | NormalizeWhitespace()) |
None
|
history
|
Optional[Union[List[Dict[str, str]], Tuple[List[Dict[str, str]], Refiner]]]
|
Conversation history. Can be: - List[Dict]: [{"role": "user", "content": "Hi"}] - Tuple[List[Dict], Refiner]: ([{"role": "user", "content": "Hi"}], StripHTML()) - Tuple[List[Dict], Pipeline]: ([{"role": "user", "content": "Hi"}], StripHTML() | NormalizeWhitespace()) |
None
|
query
|
Optional[Union[str, Tuple[str, Refiner]]]
|
Current query. Can be: - str: "What's the weather?" - Tuple[str, Refiner]: ("What's the weather?", StripHTML()) - Tuple[str, Pipeline]: ("What's the weather?", StripHTML() | NormalizeWhitespace()) |
None
|
Example (Simple - no refiners): >>> packer = MessagesPacker( ... system="You are helpful.", ... context=["
Doc 2
"], ... history=[{"role": "user", "content": "Hi"}], ... query="What's the weather?" ... ) >>> messages = packer.pack()Example (With single Refiner): >>> from prompt_refiner import MessagesPacker, StripHTML >>> packer = MessagesPacker( ... system="You are helpful.", ... context=(["
Doc 2
"], StripHTML()), ... query="What's the weather?" ... ) >>> messages = packer.pack()Example (With Pipeline - multiple refiners): >>> from prompt_refiner import MessagesPacker, StripHTML, NormalizeWhitespace, Pipeline >>> cleaner = StripHTML() | NormalizeWhitespace() >>> # Or: cleaner = Pipeline([StripHTML(), NormalizeWhitespace()]) >>> packer = MessagesPacker( ... system="You are helpful.", ... context=(["
Doc 2
"], cleaner), ... query="What's the weather?" ... ) >>> messages = packer.pack()Example (Traditional API - still supported): >>> packer = MessagesPacker() >>> packer.add("You are helpful.", role="system") >>> packer.add("Doc 1", role="context") >>> messages = packer.pack()
Source code in src/prompt_refiner/packer/messages.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
Functions
quick_pack
classmethod
One-liner to create packer and pack messages immediately.
Default refining strategies are automatically applied (same as init): - system/query: MinimalStrategy - context/history: StandardStrategy
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Optional[Union[str, Tuple[str, Refiner]]]
|
System message (str or (str, Refiner/Pipeline) tuple) |
None
|
context
|
Optional[Union[List[str], Tuple[List[str], Refiner]]]
|
Context documents (list or (list, Refiner/Pipeline) tuple) |
None
|
history
|
Optional[Union[List[Dict[str, str]], Tuple[List[Dict[str, str]], Refiner]]]
|
Conversation history (list or (list, Refiner/Pipeline) tuple) |
None
|
query
|
Optional[Union[str, Tuple[str, Refiner]]]
|
Current query (str or (str, Refiner/Pipeline) tuple) |
None
|
Returns:
| Type | Description |
|---|---|
List[Dict[str, str]]
|
Packed messages ready for LLM API |
Example (Simple): >>> messages = MessagesPacker.quick_pack( ... system="You are helpful.", ... context=["
Doc 2
"], ... query="What's the weather?" ... )Example (With single Refiner): >>> from prompt_refiner import MessagesPacker, StripHTML >>> messages = MessagesPacker.quick_pack( ... system="You are helpful.", ... context=(["
Doc 2
"], StripHTML()), ... query="What's the weather?" ... )Example (With Pipeline - multiple refiners): >>> from prompt_refiner import MessagesPacker, StripHTML, NormalizeWhitespace, Pipeline >>> cleaner = StripHTML() | NormalizeWhitespace() >>> # Or: cleaner = Pipeline([StripHTML(), NormalizeWhitespace()]) >>> messages = MessagesPacker.quick_pack( ... system="You are helpful.", ... context=(["
Doc 2
"], cleaner), ... query="What's the weather?" ... ) >>> # Ready to use: client.chat.completions.create(messages=messages)Source code in src/prompt_refiner/packer/messages.py
pack
Pack items into message format for chat APIs.
Automatically maps semantic roles to API-compatible roles: - ROLE_CONTEXT → "user" (RAG documents as user-provided context) - ROLE_QUERY → "user" (current user question) - Other roles (system, user, assistant) remain unchanged
Returns:
| Type | Description |
|---|---|
List[Dict[str, str]]
|
List of message dictionaries with 'role' and 'content' keys, |
List[Dict[str, str]]
|
ready for OpenAI, Anthropic, and other chat completion APIs. |
Example
messages = packer.pack() openai.chat.completions.create(model="gpt-4", messages=messages)
Source code in src/prompt_refiner/packer/messages.py
TextPacker
Optimized for text completion APIs (Llama Base, GPT-3). Returns str directly with multiple text formats.
prompt_refiner.packer.TextPacker
TextPacker(
track_tokens=False,
token_counter=None,
text_format=TextFormat.RAW,
separator=None,
system=None,
context=None,
history=None,
query=None,
)
Bases: BasePacker
Packer for text completion APIs.
Designed for: - Base models (Llama-2-base, GPT-3, etc.) - Completion endpoints (not chat) - Custom prompt templates
Returns: str (formatted text ready for completion API)
Supports multiple text formatting strategies to prevent instruction drifting:
- RAW: Simple concatenation with separators
- MARKDOWN: Grouped sections (INSTRUCTIONS, CONTEXT, CONVERSATION, INPUT)
- XML: Semantic
Example
from prompt_refiner import TextPacker, TextFormat
Basic usage with automatic refining
packer = TextPacker( ... text_format=TextFormat.MARKDOWN, ... system="You are helpful.", ... context=["
Doc 1", "Doc 2"], ... query="What's the weather?" ... ) prompt = packer.pack()Use directly: completion.create(prompt=prompt)
Traditional API still supported
packer = TextPacker() packer.add("System prompt", role="system") prompt = packer.pack()
Initialize text packer.
Default Refining Strategies: When no explicit refiner is provided, automatic refining strategies are applied: - system/query: MinimalStrategy (StripHTML + NormalizeWhitespace) - context/history: StandardStrategy (StripHTML + NormalizeWhitespace + Deduplicate)
To override defaults, provide explicit refiner tuple: (content, refiner). For raw content with no refinement, use .add() method with refine_with=None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
track_tokens
|
bool
|
Enable token tracking to measure refinement effectiveness |
False
|
token_counter
|
Optional[Callable[[str], int]]
|
Function to count tokens (required if track_tokens=True) |
None
|
text_format
|
TextFormat
|
Text formatting strategy (RAW, MARKDOWN, XML) |
RAW
|
separator
|
Optional[str]
|
String to join items (default: "\n\n" for clarity) |
None
|
system
|
Optional[Union[str, Tuple[str, Refiner]]]
|
System message. Can be: - str: "You are helpful" - Tuple[str, Refiner]: ("You are helpful", StripHTML()) - Tuple[str, Pipeline]: ("You are helpful", StripHTML() | NormalizeWhitespace()) |
None
|
context
|
Optional[Union[List[str], Tuple[List[str], Refiner]]]
|
Context documents. Can be: - List[str]: ["doc1", "doc2"] - Tuple[List[str], Refiner]: (["doc1", "doc2"], StripHTML()) - Tuple[List[str], Pipeline]: (["doc1", "doc2"], StripHTML() | NormalizeWhitespace()) |
None
|
history
|
Optional[Union[List[Dict[str, str]], Tuple[List[Dict[str, str]], Refiner]]]
|
Conversation history. Can be: - List[Dict]: [{"role": "user", "content": "Hi"}] - Tuple[List[Dict], Refiner]: ([{"role": "user", "content": "Hi"}], StripHTML()) - Tuple[List[Dict], Pipeline]: ([{"role": "user", "content": "Hi"}], StripHTML() | NormalizeWhitespace()) |
None
|
query
|
Optional[Union[str, Tuple[str, Refiner]]]
|
Current query. Can be: - str: "What's the weather?" - Tuple[str, Refiner]: ("What's the weather?", StripHTML()) - Tuple[str, Pipeline]: ("What's the weather?", StripHTML() | NormalizeWhitespace()) |
None
|
Example (Simple - no refiners): >>> packer = TextPacker( ... text_format=TextFormat.MARKDOWN, ... system="You are helpful.", ... context=["Doc 1", "Doc 2"], ... query="What's the weather?" ... ) >>> prompt = packer.pack()
Example (With single Refiner): >>> from prompt_refiner import TextPacker, StripHTML >>> packer = TextPacker( ... text_format=TextFormat.MARKDOWN, ... system="You are helpful.", ... context=(["
Example (With Pipeline - multiple refiners): >>> from prompt_refiner import TextPacker, StripHTML, NormalizeWhitespace, Pipeline >>> cleaner = StripHTML() | NormalizeWhitespace() >>> # Or: cleaner = Pipeline([StripHTML(), NormalizeWhitespace()]) >>> packer = TextPacker( ... text_format=TextFormat.MARKDOWN, ... system="You are helpful.", ... context=(["
Source code in src/prompt_refiner/packer/text.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | |
Functions
quick_pack
classmethod
quick_pack(
system=None,
context=None,
history=None,
query=None,
text_format=TextFormat.RAW,
separator=None,
)
One-liner to create packer and pack text immediately.
Default refining strategies are automatically applied (same as init): - system/query: MinimalStrategy - context/history: StandardStrategy
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
Optional[Union[str, Tuple[str, Refiner]]]
|
System message (str or (str, Refiner/Pipeline) tuple) |
None
|
context
|
Optional[Union[List[str], Tuple[List[str], Refiner]]]
|
Context documents (list or (list, Refiner/Pipeline) tuple) |
None
|
history
|
Optional[Union[List[Dict[str, str]], Tuple[List[Dict[str, str]], Refiner]]]
|
Conversation history (list or (list, Refiner/Pipeline) tuple) |
None
|
query
|
Optional[Union[str, Tuple[str, Refiner]]]
|
Current query (str or (str, Refiner/Pipeline) tuple) |
None
|
text_format
|
TextFormat
|
Text formatting strategy (RAW, MARKDOWN, XML) |
RAW
|
separator
|
Optional[str]
|
String to join items |
None
|
Returns:
| Type | Description |
|---|---|
str
|
Packed text ready for completion API |
Example (Simple): >>> prompt = TextPacker.quick_pack( ... text_format=TextFormat.MARKDOWN, ... system="You are helpful.", ... context=["Doc 1", "Doc 2"], ... query="What's the weather?" ... )
Example (With single Refiner): >>> from prompt_refiner import TextPacker, StripHTML, TextFormat >>> prompt = TextPacker.quick_pack( ... text_format=TextFormat.MARKDOWN, ... system="You are helpful.", ... context=(["
Example (With Pipeline - multiple refiners): >>> from prompt_refiner import ( ... TextPacker, StripHTML, NormalizeWhitespace, TextFormat, Pipeline ... ) >>> cleaner = StripHTML() | NormalizeWhitespace() >>> # Or: cleaner = Pipeline([StripHTML(), NormalizeWhitespace()]) >>> prompt = TextPacker.quick_pack( ... text_format=TextFormat.MARKDOWN, ... system="You are helpful.", ... context=(["
Source code in src/prompt_refiner/packer/text.py
pack
Pack items into formatted text for completion APIs.
MARKDOWN format uses grouped sections: - INSTRUCTIONS: System prompts (ROLE_SYSTEM) - CONTEXT: RAG documents (ROLE_CONTEXT) - CONVERSATION: User/assistant history (ROLE_USER, ROLE_ASSISTANT) - INPUT: Current user query (ROLE_QUERY)
Returns:
| Type | Description |
|---|---|
str
|
Formatted text string ready for completion API |
Example
prompt = packer.pack() response = completion.create(model="llama-2-70b", prompt=prompt)
Source code in src/prompt_refiner/packer/text.py
BasePacker
Abstract base class providing common packer functionality. You typically won't use this directly.
prompt_refiner.packer.BasePacker
Bases: ABC
Abstract base class for prompt packers.
Provides common functionality: - Adding items with priorities - JIT refinement with strategies/operations - Priority-based sorting
Subclasses must implement: - pack(): Format and return packed items
Initialize packer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
track_tokens
|
bool
|
Enable token tracking to measure refinement effectiveness |
False
|
token_counter
|
Optional[Callable[[str], int]]
|
Function to count tokens (required if track_tokens=True) |
None
|
Source code in src/prompt_refiner/packer/base.py
Attributes
token_stats
property
Get token savings statistics (only available when track_tokens=True).
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dictionary with the following keys: - raw_tokens: int - Total tokens before refinement - refined_tokens: int - Total tokens after refinement - saved_tokens: int - Tokens saved by refinement - saving_percent: str - Percentage saved (e.g., "25.5%") |
Raises:
| Type | Description |
|---|---|
ValueError
|
If token tracking is not enabled |
Example
packer = MessagesPacker(track_tokens=True, token_counter=character_based_counter) packer.add("
Hello", role="user", refine_with=StripHTML()) stats = packer.token_stats print(stats)
Functions
add
Add an item to the packer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
Text content to add |
required |
role
|
RoleType
|
Semantic role (required). Use ROLE_* constants: - ROLE_SYSTEM: System instructions - ROLE_QUERY: Current user question - ROLE_CONTEXT: RAG retrieved documents - ROLE_USER: User messages in conversation history - ROLE_ASSISTANT: Assistant messages in history |
required |
priority
|
Optional[int]
|
Priority level (use PRIORITY_* constants). If None, infers from role: - ROLE_SYSTEM → PRIORITY_SYSTEM (0) - ROLE_QUERY → PRIORITY_QUERY (10) - ROLE_CONTEXT → PRIORITY_HIGH (20) - ROLE_USER/ROLE_ASSISTANT → PRIORITY_LOW (40) - Other roles → PRIORITY_MEDIUM (30) |
None
|
refine_with
|
Optional[Refiner]
|
Optional refiner or pipeline to apply before adding. Can be: - Single refiner: StripHTML() - Pipeline: StripHTML() | NormalizeWhitespace() - Pipeline from list: Pipeline([StripHTML(), NormalizeWhitespace()]) |
None
|
Returns:
| Type | Description |
|---|---|
BasePacker
|
Self for method chaining |
Source code in src/prompt_refiner/packer/base.py
add_messages
Batch add messages (convenience method).
Defaults to PRIORITY_LOW because conversation history is usually the first to be dropped in favor of RAG context and current queries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
List[Dict[str, str]]
|
List of message dicts with 'role' and 'content' keys |
required |
priority
|
int
|
Priority level for all messages (default: PRIORITY_LOW for history) |
PRIORITY_LOW
|
Returns:
| Type | Description |
|---|---|
BasePacker
|
Self for method chaining |
Source code in src/prompt_refiner/packer/base.py
reset
Reset the packer, removing all items and token stats.
Returns:
| Type | Description |
|---|---|
BasePacker
|
Self for method chaining |
Source code in src/prompt_refiner/packer/base.py
get_items
Get information about all added items.
Returns:
| Type | Description |
|---|---|
List[dict]
|
List of dictionaries containing item metadata |
Source code in src/prompt_refiner/packer/base.py
pack
abstractmethod
Pack items into final format.
Subclasses must implement this to return format-specific output: - MessagesPacker: Returns List[Dict[str, str]] - TextPacker: Returns str
Source code in src/prompt_refiner/packer/base.py
Constants
Semantic Role Constants (Recommended)
from prompt_refiner import (
ROLE_SYSTEM, # "system" - System instructions (auto: PRIORITY_SYSTEM = 0)
ROLE_QUERY, # "query" - Current user question (auto: PRIORITY_QUERY = 10)
ROLE_CONTEXT, # "context" - RAG documents (auto: PRIORITY_HIGH = 20)
ROLE_USER, # "user" - User messages in history (auto: PRIORITY_LOW = 40)
ROLE_ASSISTANT, # "assistant" - Assistant messages in history (auto: PRIORITY_LOW = 40)
)
Priority Constants (Optional)
from prompt_refiner import (
PRIORITY_SYSTEM, # 0 - Absolute must-have (system prompts)
PRIORITY_QUERY, # 10 - Current user query (critical for response)
PRIORITY_HIGH, # 20 - Important context (core RAG documents)
PRIORITY_MEDIUM, # 30 - Normal priority (general RAG documents)
PRIORITY_LOW, # 40 - Optional content (old conversation history)
)
Smart Priority Defaults
You usually don't need to specify priority! Just use semantic roles and priority is auto-inferred:
# Recommended: Use semantic roles (priority auto-inferred)
packer.add("System prompt", role=ROLE_SYSTEM) # Auto: PRIORITY_SYSTEM (0)
packer.add("User query", role=ROLE_QUERY) # Auto: PRIORITY_QUERY (10)
packer.add("RAG doc", role=ROLE_CONTEXT) # Auto: PRIORITY_HIGH (20)
# Advanced: Override priority if needed
packer.add("Urgent RAG doc", role=ROLE_CONTEXT, priority=PRIORITY_QUERY)
TextFormat Enum
from prompt_refiner import TextFormat
TextFormat.RAW # No delimiters, simple concatenation
TextFormat.MARKDOWN # Use ### ROLE: headers (grouped sections in v0.1.3+)
TextFormat.XML # Use <role>content</role> tags
Default Refining Strategies
Version 0.2.1+ introduces automatic refining strategies. When no explicit refiner is provided, packers apply sensible defaults:
system/query: MinimalStrategy (StripHTML + NormalizeWhitespace)context/history: StandardStrategy (StripHTML + NormalizeWhitespace + Deduplicate)
from prompt_refiner import MessagesPacker
# Automatic refining with defaults
packer = MessagesPacker(
system="<p>You are helpful.</p>", # Auto: MinimalStrategy
context=["<div>Doc 1</div>"], # Auto: StandardStrategy
query="<span>What's the weather?</span>" # Auto: MinimalStrategy
)
# Override with custom pipeline
packer = MessagesPacker(
context=(["<div>Doc</div>"], StripHTML() | NormalizeWhitespace())
)
Token Savings Tracking
Version 0.1.5+ introduces automatic token savings tracking to measure the optimization impact of refine_with operations.
Enable Tracking
# Opt-in to tracking with track_savings parameter
packer = MessagesPacker(track_savings=True)
# Add items with refinement
packer.add(
"<div> Messy HTML </div>",
role=ROLE_CONTEXT,
refine_with=[StripHTML(), NormalizeWhitespace()]
)
# Get savings statistics
savings = packer.get_token_savings()
# Returns: {
# 'original_tokens': 25, # Tokens before refinement
# 'refined_tokens': 12, # Tokens after refinement
# 'saved_tokens': 13, # Tokens saved
# 'saving_percent': 52.0, # Percentage saved
# 'items_refined': 1 # Count of refined items
# }
Key Features
- Opt-in: Disabled by default (no overhead when not needed)
- Automatic aggregation: Tracks all items that use
refine_with - Per-item and total: Aggregates savings across all refined items
- Works with both packers: Available for
MessagesPackerandTextPacker
Example with Real API
from prompt_refiner import MessagesPacker, StripHTML
from openai import OpenAI
client = OpenAI()
packer = MessagesPacker(track_savings=True)
# Add multiple RAG documents with automatic cleaning
for doc in scraped_html_docs:
packer.add(doc, role="context", refine_with=StripHTML())
# Pack messages and check savings
messages = packer.pack()
savings = packer.get_token_savings()
print(f"Saved {savings['saved_tokens']} tokens ({savings['saving_percent']:.1f}%)")
# Example output: "Saved 1,234 tokens (23.5%)"
# Use cleaned messages with API
response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
When to Use
✅ Use token savings tracking when: - You want to measure ROI of optimization efforts - Demonstrating token savings to stakeholders - A/B testing different refinement strategies - Monitoring optimization impact in production
❌ Skip tracking when:
- Not using refine_with parameter (returns empty dict)
- Performance is absolutely critical (negligible overhead, but why enable?)
- You don't need savings metrics
Combine with CountTokens
For pipeline optimization (not packer), use CountTokens instead:
MessagesPacker Examples
Basic Usage
from prompt_refiner import MessagesPacker
packer = MessagesPacker()
packer.add(
"You are a helpful assistant.",
role="system" # Auto: PRIORITY_SYSTEM (0)
)
packer.add(
"What is prompt-refiner?",
role="query" # Auto: PRIORITY_QUERY (10)
)
messages = packer.pack() # List[Dict[str, str]]
# Use directly: openai.chat.completions.create(messages=messages)
RAG with Conversation History
from prompt_refiner import MessagesPacker, StripHTML
packer = MessagesPacker()
# System prompt
packer.add(
"Answer based on provided context.",
role="system" # Auto: PRIORITY_SYSTEM (0)
)
# RAG documents with JIT cleaning
packer.add(
"<p>Prompt-refiner is a library...</p>",
role="context", # Auto: PRIORITY_HIGH (20)
refine_with=StripHTML()
)
# Old conversation history
old_messages = [
{"role": "user", "content": "What is this library?"},
{"role": "assistant", "content": "It's a tool for optimizing prompts."}
]
packer.add_messages(old_messages) # Auto: PRIORITY_LOW (40) for history
# Current query
packer.add(
"How does it reduce costs?",
role="query" # Auto: PRIORITY_QUERY (10)
)
messages = packer.pack()
TextPacker Examples
Basic Usage
from prompt_refiner import TextPacker, TextFormat
packer = TextPacker(text_format=TextFormat.MARKDOWN)
packer.add(
"You are a QA assistant.",
role="system" # Auto: PRIORITY_SYSTEM (0)
)
packer.add(
"Context: Prompt-refiner is a library...",
role="context" # Auto: PRIORITY_HIGH (20)
)
packer.add(
"What is prompt-refiner?",
role="query" # Auto: PRIORITY_QUERY (10)
)
prompt = packer.pack() # str
# Use with: completion.create(prompt=prompt)
Text Format Comparison
from prompt_refiner import TextPacker, TextFormat
# RAW format (simple concatenation)
packer = TextPacker(text_format=TextFormat.RAW)
packer.add("System prompt", role="system")
packer.add("User query", role="query")
prompt = packer.pack()
# Output:
# System prompt
#
# User query
# MARKDOWN format (grouped sections in v0.1.3+)
packer = TextPacker(text_format=TextFormat.MARKDOWN)
packer.add("System prompt", role="system")
packer.add("Doc 1", role="context")
packer.add("Doc 2", role="context")
packer.add("User query", role="query")
prompt = packer.pack()
# Output:
# ### INSTRUCTIONS:
# System prompt
#
# ### CONTEXT:
# - Doc 1
# - Doc 2
#
# ### INPUT:
# User query
# XML format
packer = TextPacker(text_format=TextFormat.XML)
packer.add("System prompt", role="system")
packer.add("User query", role="query")
prompt = packer.pack()
# Output:
# <system>
# System prompt
# </system>
#
# <query>
# User query
# </query>
Common Features
JIT Refinement
Both packers support Just-In-Time refinement:
from prompt_refiner import StripHTML, NormalizeWhitespace
# Single operation
packer.add(
"<div>HTML content</div>",
role="context",
refine_with=StripHTML()
)
# Multiple operations
packer.add(
"<p> Messy HTML </p>",
role="context",
refine_with=[StripHTML(), NormalizeWhitespace()]
)
Method Chaining
from prompt_refiner import MessagesPacker
messages = (
MessagesPacker()
.add("System prompt", role="system")
.add("User query", role="query")
.pack()
)
Inspection
from prompt_refiner import MessagesPacker
packer = MessagesPacker()
packer.add("Item 1", role="system")
packer.add("Item 2", role="query")
# Inspect items before packing
items = packer.get_items()
for item in items:
print(f"Priority: {item['priority']}, Role: {item['role']}")
Reset
from prompt_refiner import MessagesPacker
packer = MessagesPacker()
packer.add("First batch", role="context")
messages1 = packer.pack()
# Clear and reuse
packer.reset()
packer.add("Second batch", role="context")
messages2 = packer.pack()
Algorithm Details
- Add Phase: Items are added with priorities, optional roles, and automatic/explicit refinement
- Refinement (v0.2.1+):
- Default strategies applied automatically (MinimalStrategy for system/query, StandardStrategy for context/history)
- Override with explicit refiner:
context=(docs, StripHTML() | NormalizeWhitespace()) - Skip refinement: Use
.add()method withrefine_with=None - Token Counting: Content tokens counted for savings tracking (when enabled)
- Sort Phase: Items are sorted by priority (lower number = higher priority), stable sort preserves insertion order
- Order Restoration: All items restored to insertion order for natural reading flow
- Format Phase:
- MessagesPacker: Returns
List[Dict[str, str]](semantic roles mapped to API roles) - TextPacker: Returns formatted
strbased ontext_format(RAW, MARKDOWN, or XML)
Tips
Choose the Right Packer
- Use MessagesPacker for chat APIs (OpenAI, Anthropic)
- Use TextPacker for completion APIs (Llama Base, GPT-3)
Use Semantic Roles (Recommended)
Semantic roles auto-infer priorities, making code clearer:
ROLE_SYSTEM: System instructions → PRIORITY_SYSTEM (0)ROLE_QUERY: Current user question → PRIORITY_QUERY (10)ROLE_CONTEXT: RAG documents → PRIORITY_HIGH (20)ROLE_USER/ROLE_ASSISTANT: Conversation history → PRIORITY_LOW (40)
Override Priority When Needed
Most of the time semantic roles are enough, but you can override:
Clean Before Packing
Use refine_with to clean items before token counting: