Advanced Features¶
Overview¶
The Chat Template System provides advanced features for fine-grained control over template behavior, tool integration, and system message processing. This guide covers the sophisticated capabilities that make the system powerful and flexible.
Tool Policy System¶
Tool Placement Strategies¶
The system supports multiple strategies for where and how tools are integrated into prompts:
from chat_bricks import ToolPlacement
# 1. SYSTEM placement - tools appear in system message
system_placement = ToolPlacement.SYSTEM
# 2. FIRST_USER placement - tools appear with first user message
first_user_placement = ToolPlacement.FIRST_USER
# 3. LAST_USER placement - tools appear with last user message
last_user_placement = ToolPlacement.LAST_USER
Tool Formatters¶
Different strategies for formatting tool definitions:
JSON Formatters¶
from chat_bricks import (
JsonFormatter, JsonMinifiedFormatter, JsonIndentedFormatter, JsonCompactFormatter
)
# Standard JSON formatter with configurable options
json_formatter = JsonFormatter(
indent=2, # Pretty-printed with 2-space indent
separators=(",", ":"), # Standard JSON separators
joiner="\n\n", # Join multiple tools with double newlines
format_as_list=False # Format as individual JSON objects
)
# Minified JSON (single line, no whitespace)
minified_formatter = JsonMinifiedFormatter(joiner="\n")
# Indented JSON (pretty-printed)
indented_formatter = JsonIndentedFormatter(indent=4, joiner="\n\n")
# Compact JSON (single array)
compact_formatter = JsonCompactFormatter(format_as_list=True)
YAML Formatter¶
from chat_bricks import YamlFormatter
# YAML formatting (requires PyYAML)
yaml_formatter = YamlFormatter()
Custom Formatters¶
from chat_bricks import ToolFormatter, ToolPolicy, ToolPlacement
class CustomToolFormatter(ToolFormatter):
def format(self, tools):
"""Custom formatting logic"""
formatted_tools = []
for tool in tools:
if "function" in tool:
func = tool["function"]
formatted = f"Function: {func['name']}\n"
formatted += f"Description: {func['description']}\n"
formatted += f"Parameters: {func['parameters']}\n"
formatted_tools.append(formatted)
return "\n---\n".join(formatted_tools)
def jinja(self):
"""Jinja template for custom formatting"""
return """{% for tool in tools %}
Function: {{ tool.function.name }}
Description: {{ tool.function.description }}
Parameters: {{ tool.function.parameters }}
{% if not loop.last %}---{% endif %}
{% endfor %}"""
# Use custom formatter
custom_tool_policy = ToolPolicy(
placement=ToolPlacement.SYSTEM,
formatter=CustomToolFormatter()
)
Tool Content Processors¶
Process tool content before formatting:
from chat_bricks import ToolContentProcessor, ToolPolicy, ToolPlacement, JsonIndentedFormatter
class ToolFilterProcessor(ToolContentProcessor):
"""Filter tools based on certain criteria"""
def __init__(self, allowed_categories=None):
self.allowed_categories = allowed_categories or []
def __call__(self, tool):
"""Filter tool based on category"""
if not self.allowed_categories:
return tool
# Check if tool has category and it's allowed
tool_category = tool.get("category", "general")
if tool_category in self.allowed_categories:
return tool
return None
def jinja(self):
"""Jinja template for filtering"""
return "{{ tool if tool.category in ['allowed_category1', 'allowed_category2'] else none }}"
# Use content processor
filtered_tool_policy = ToolPolicy(
placement=ToolPlacement.SYSTEM,
formatter=JsonIndentedFormatter(),
content_processor=ToolFilterProcessor(["search", "calculation"])
)
Skill Policy System¶
Skills are a lightweight catalogue concept — each skill has a name and
description, and the list is advertised in the system prompt (typically next
to a load_skill tool). Unlike tools, skills always live in the system message
— there is no placement variation.
How Skills Render¶
Three pieces decide what the skill block looks like:
{skills}placeholder insystem_template— where the block lives.skills_template— wraps the joined list, e.g."# Skills\n<skills>\n{skills}\n</skills>".single_skill_template(orSkillPolicy.single_skill_template) — wraps one entry, defaulting to"- {name}: {description}".
If skills_template is None, the template doesn't render skills and a
skills= argument at render time is silently dropped.
SkillPolicy¶
from chat_bricks import Template
from chat_bricks.policies import SkillPolicy
# Default policy — one entry per line, "- name: description"
default_skill_policy = SkillPolicy()
# Custom row format and a different joiner
custom_skill_policy = SkillPolicy(
single_skill_template="* {name} :: {description}",
joiner="\n",
)
# With a content processor (e.g. truncating long descriptions)
def truncate_description(skill, limit=80):
desc = skill.get("description", "")
if len(desc) > limit:
skill = {**skill, "description": desc[: limit - 1] + "…"}
return skill
policy_with_processor = SkillPolicy(content_processor=truncate_description)
template = Template(
name="my-skills",
system_template="<|im_start|>system\n{system_message}{skills}<|im_end|>\n",
skills_template="\n\n# Skills\n<skills>\n{skills}\n</skills>",
skill_policy=custom_skill_policy,
user_template="<|im_start|>user\n{content}<|im_end|>\n",
assistant_template="<|im_start|>assistant\n{content}<|im_end|>\n",
stop_words=["<|im_end|>"],
)
Skill Entries¶
Skill entries may be plain dicts or any object that exposes .name and
.description attributes:
from dataclasses import dataclass
@dataclass
class Skill:
name: str
description: str
skills = [
{"name": "add-numbers", "description": "Adds two integers."},
Skill("word-count", "Counts words in text."),
]
chat = Chat(template="my-skills", messages=messages, skills=skills)
print(chat.prompt())
Missing name raises TypeError — description defaults to empty if absent.
System Policy System¶
System Message Control¶
Fine-grained control over system message behavior:
from chat_bricks import SystemPolicy
# Basic system policy
basic_policy = SystemPolicy(
use_system=True, # Always include system message
use_system_without_system_message=True, # Include system even without explicit message
content_processor=None # No content processing
)
# Conditional system policy
conditional_policy = SystemPolicy(
use_system=True, # Include system when present
use_system_without_system_message=False, # Don't include system if no message
content_processor=None
)
# No system policy
no_system_policy = SystemPolicy(
use_system=False, # Never include system message
use_system_without_system_message=False,
content_processor=None
)
System Content Processors¶
Transform system messages before rendering:
Built-in Processors¶
from chat_bricks import Llama32DateProcessor
# Llama 3.2 date processor (adds current date)
llama_date_policy = SystemPolicy(
use_system=True,
use_system_without_system_message=True,
content_processor=Llama32DateProcessor()
)
Custom Content Processors¶
from chat_bricks import SystemContentProcessor, SystemPolicy
class EnvironmentAwareProcessor(SystemContentProcessor):
"""Add environment information to system messages"""
def __init__(self, environment="production"):
self.environment = environment
def __call__(self, system_message):
"""Add environment context"""
env_info = f"[Environment: {self.environment}]"
return f"{env_info}\n{system_message}"
def jinja(self):
"""Jinja template for environment awareness"""
return """[Environment: {{ environment | default('production') }}]
{{ system_message }}"""
# Use custom processor
env_policy = SystemPolicy(
use_system=True,
use_system_without_system_message=True,
content_processor=EnvironmentAwareProcessor("development")
)
Lambda Processors¶
# Simple lambda processor
lambda_policy = SystemPolicy(
use_system=True,
use_system_without_system_message=True,
content_processor=lambda msg: f"[{datetime.now().strftime('%H:%M')}] {msg}"
)
Global Policy Configuration¶
Template-Wide Settings¶
from chat_bricks import GlobalPolicy
# Add prefix to all prompts
prefix_policy = GlobalPolicy(prefix="<|begin_of_text|>")
Advanced Template Features¶
Conditional Templates¶
The {tools} and {skills} placeholders in system_template expand to empty
strings when no tools/skills are passed, so one template handles both the bare
and section-enabled cases without an _with_tools variant.
from chat_bricks import Template
conditional_template = Template(
name="conditional",
system_template="You are a helpful assistant.{tools}",
tools_template=" with tools: {tools}",
user_template="User: {content}",
user_template_with_tools="User: {content}\n\nAvailable tools: {tools}",
assistant_template="Assistant: {content}",
observations_template="Tool: {observation}"
)
Dynamic Template Generation¶
def create_dynamic_template(base_name, capabilities):
"""Create template based on capabilities"""
# Base templates
system_base = "You are a helpful assistant."
user_base = "User: {content}"
assistant_base = "Assistant: {content}"
# Add tool support if needed
if "tools" in capabilities:
system_base += "\n\nYou have access to tools: {tools}"
user_base += "\n\nAvailable tools: {tools}"
# Add vision support if needed
if "vision" in capabilities:
system_base += "\n\nYou can process images and videos."
return Template(
name=f"{base_name}-{'-'.join(capabilities)}",
system_template=system_base,
user_template=user_base,
assistant_template=assistant_base,
vision_start="<vision>" if "vision" in capabilities else None,
vision_end="</vision>" if "vision" in capabilities else None,
image_token="<image>" if "vision" in capabilities else None,
video_token="<video>" if "vision" in capabilities else None
)
# Create specialized templates
coding_template = create_dynamic_template("coding", ["tools"])
vision_template = create_dynamic_template("vision", ["vision"])
full_template = create_dynamic_template("full", ["tools", "vision"])
Policy Composition and Inheritance¶
Combining Policies¶
from chat_bricks import ToolPolicy, ToolPlacement, JsonIndentedFormatter
# Create a base tool policy
base_tool_policy = ToolPolicy(
placement=ToolPlacement.SYSTEM,
formatter=JsonIndentedFormatter(indent=2)
)
# Create a specialized tool policy
specialized_tool_policy = ToolPolicy(
placement=ToolPlacement.FIRST_USER, # Override placement
formatter=base_tool_policy.formatter, # Inherit formatter
content_processor=ToolFilterProcessor(["search"]) # Add processor
)
Template Policy Inheritance¶
# Base template with policies
base_template = Template(
name="base",
system_template="Base: {system_message}",
user_template="User: {content}",
assistant_template="Assistant: {content}",
tool_policy=ToolPolicy(
placement=ToolPlacement.SYSTEM,
formatter=JsonFormatter()
),
system_policy=SystemPolicy(
use_system=True,
use_system_without_system_message=True
)
)
# Specialized template inheriting policies
specialized_template = Template(
name="specialized",
system_template="Specialized: {system_message}",
user_template=base_template.user_template,
assistant_template=base_template.assistant_template,
tool_policy=base_template.tool_policy, # Inherit tool policy
system_policy=base_template.system_policy # Inherit system policy
)
Advanced Tool Integration¶
Tool Validation¶
from chat_bricks import ToolPolicy, ToolPlacement, JsonFormatter
class ToolValidator:
"""Validate tool definitions"""
@staticmethod
def validate_tool(tool):
"""Validate a single tool"""
required_fields = ["function", "name", "parameters"]
if "function" in tool:
func = tool["function"]
for field in required_fields:
if field not in func:
raise ValueError(f"Missing required field: {field}")
else:
for field in required_fields:
if field not in tool:
raise ValueError(f"Missing required field: {field}")
return tool
# Use validator in tool policy
validated_tool_policy = ToolPolicy(
placement=ToolPlacement.SYSTEM,
formatter=JsonFormatter(),
content_processor=ToolValidator.validate_tool
)
Best Practices for Advanced Features¶
1. Policy Design¶
- Keep policies focused and single-purpose
- Use composition over inheritance when possible
- Document policy behavior clearly
2. Tool Integration¶
- Choose appropriate placement strategies for your use case
- Validate tool definitions before processing
- Use content processors for tool transformation
3. System Message Management¶
- Use content processors for dynamic system content
- Consider when system messages should appear
- Balance flexibility with consistency
4. Performance Considerations¶
- Cache frequently used templates and policies
- Use lazy evaluation for expensive operations
- Profile template rendering performance
5. Testing Advanced Features¶
- Test policy combinations thoroughly
- Verify tool placement strategies work correctly
- Test content processors with various inputs
This advanced features guide covers the sophisticated capabilities that make the Chat Template System powerful and flexible. Use these features to create highly customized templates that meet your specific requirements.