Directive Processor API Reference¶
The Directive Processor handles special instructions in prompts that begin with //
and enable powerful prompt composition capabilities.
Core Classes¶
PromptManager::DirectiveProcessor
¶
The main class responsible for processing directives within prompts.
Constructor¶
processor = PromptManager::DirectiveProcessor.new(
storage: storage_adapter,
max_depth: 10,
timeout: 30
)
Parameters:
- storage
(Storage::Base): Storage adapter for resolving includes
- max_depth
(Integer): Maximum include depth to prevent circular references (default: 10)
- timeout
(Numeric): Processing timeout in seconds (default: 30)
Instance Methods¶
process(content, context = {})
¶
Processes all directives in the given content.
Parameters:
- content
(String): The prompt content containing directives
- context
(Hash): Processing context and variables
Returns: String - Processed content with directives resolved
Raises:
- PromptManager::DirectiveProcessingError
- If directive processing fails
- PromptManager::CircularIncludeError
- If circular includes are detected
processor = PromptManager::DirectiveProcessor.new(storage: adapter)
result = processor.process("//include header.txt\nHello World!")
register_directive(name, handler)
¶
Registers a custom directive handler.
Parameters:
- name
(String): Directive name (without //)
- handler
(Proc): Handler that processes the directive
processor.register_directive('timestamp') do |args, context|
Time.current.strftime('%Y-%m-%d %H:%M:%S')
end
Built-in Directives¶
//include
(alias: //import
)¶
Includes content from another prompt file.
Syntax:
Features:
- Parameter substitution in paths: //include templates/[TEMPLATE_TYPE].txt
- Relative and absolute path resolution
- Circular include detection
- Nested include support
Examples:
# Basic include
//include common/header.txt
# With parameter substitution
//include templates/[EMAIL_TYPE].txt
# Nested directory structure
//include emails/marketing/[CAMPAIGN_TYPE]/template.txt
//set
¶
Sets variables for use within the current prompt.
Syntax:
Examples:
//set COMPANY_NAME Acme Corporation
//set SUPPORT_EMAIL support@[COMPANY_DOMAIN]
//set GREETING Hello [CUSTOMER_NAME]
Your message: [GREETING]
Contact us: [SUPPORT_EMAIL]
//if
/ //endif
¶
Conditional content inclusion.
Syntax:
Examples:
//if [USER_TYPE] == 'premium'
🌟 Premium features are available!
//endif
//if [ORDER_TOTAL] > 100
🚚 Free shipping applied!
//endif
Custom Directive Development¶
Simple Directive Handler¶
# Register a simple directive
processor.register_directive('upper') do |args, context|
args.upcase
end
# Usage in prompt:
# //upper hello world
# Result: HELLO WORLD
Complex Directive Handler¶
# Register directive with parameter processing
processor.register_directive('format_currency') do |args, context|
amount, currency = args.split(',').map(&:strip)
formatted_amount = sprintf('%.2f', amount.to_f)
case currency.downcase
when 'usd', '$'
"$#{formatted_amount}"
when 'eur', '€'
"€#{formatted_amount}"
else
"#{formatted_amount} #{currency}"
end
end
# Usage in prompt:
# //format_currency [ORDER_TOTAL], USD
# Result: $123.45
Directive with Context Access¶
processor.register_directive('user_greeting') do |args, context|
user_name = context.dig(:parameters, :user_name) || 'Guest'
time_of_day = Time.current.hour < 12 ? 'morning' : 'afternoon'
"Good #{time_of_day}, #{user_name}!"
end
# Usage in prompt:
# //user_greeting
# Result: Good morning, Alice!
Error Handling¶
Directive Processing Errors¶
begin
result = processor.process(content)
rescue PromptManager::DirectiveProcessingError => e
puts "Directive error at line #{e.line_number}: #{e.message}"
puts "Directive: #{e.directive}"
rescue PromptManager::CircularIncludeError => e
puts "Circular include detected: #{e.include_chain.join(' -> ')}"
end
Custom Error Handling¶
processor.register_directive('safe_include') do |args, context|
begin
storage.read(args)
rescue PromptManager::PromptNotFoundError
"<!-- Template #{args} not found -->"
end
end
Advanced Features¶
Conditional Directives¶
processor.register_directive('feature_flag') do |args, context|
feature_name, content = args.split(':', 2)
if FeatureFlag.enabled?(feature_name)
processor.process(content.strip, context)
else
''
end
end
# Usage:
# //feature_flag new_ui: Welcome to our new interface!
Loop Directives¶
processor.register_directive('foreach') do |args, context|
array_name, template = args.split(':', 2)
array_data = context.dig(:parameters, array_name.to_sym) || []
array_data.map.with_index do |item, index|
item_context = context.merge(
parameters: context[:parameters].merge(
item: item,
index: index,
first: index == 0,
last: index == array_data.length - 1
)
)
processor.process(template.strip, item_context)
end.join("\n")
end
# Usage:
# //foreach items: - [ITEM.NAME]: $[ITEM.PRICE]
Template Inheritance¶
class TemplateInheritanceProcessor < PromptManager::DirectiveProcessor
def initialize(**options)
super(**options)
register_built_in_directives
end
private
def register_built_in_directives
register_directive('extends') do |args, context|
parent_content = storage.read(args)
context[:parent_content] = parent_content
'' # Don't include anything at this point
end
register_directive('block') do |args, context|
block_name, content = args.split(':', 2)
context[:blocks] ||= {}
context[:blocks][block_name] = content.strip
'' # Blocks are processed later
end
register_directive('yield') do |args, context|
block_name = args.strip
context.dig(:blocks, block_name) || ''
end
end
def process(content, context = {})
# First pass: extract blocks and parent template
super(content, context)
# Second pass: process parent template with blocks
if context[:parent_content]
super(context[:parent_content], context)
else
super(content, context)
end
end
end
# Usage:
# child.txt:
# //extends parent.txt
# //block content: This is child content
# //block title: Child Page
# parent.txt:
# <h1>//yield title</h1>
# <div>//yield content</div>
Configuration¶
Global Configuration¶
PromptManager.configure do |config|
config.directive_processor_class = CustomDirectiveProcessor
config.max_include_depth = 5
config.directive_timeout = 60
end
Custom Processor¶
class CustomDirectiveProcessor < PromptManager::DirectiveProcessor
def initialize(**options)
super(**options)
register_custom_directives
end
private
def register_custom_directives
register_directive('env') { |args, context| ENV[args] }
register_directive('random') { |args, context| rand(args.to_i) }
register_directive('uuid') { |args, context| SecureRandom.uuid }
end
end
Performance Optimization¶
Caching Directive Results¶
class CachedDirectiveProcessor < PromptManager::DirectiveProcessor
def initialize(**options)
super(**options)
@directive_cache = {}
end
def register_directive(name, &handler)
cached_handler = lambda do |args, context|
cache_key = "#{name}:#{args}:#{context.hash}"
@directive_cache[cache_key] ||= handler.call(args, context)
end
super(name, &cached_handler)
end
def clear_cache
@directive_cache.clear
end
end
Parallel Processing¶
class ParallelDirectiveProcessor < PromptManager::DirectiveProcessor
def process_includes(content, context)
includes = extract_includes(content)
# Process includes in parallel
results = Parallel.map(includes) do |include_directive|
process_single_include(include_directive, context)
end
# Replace includes with results
replace_includes(content, includes, results)
end
end
Testing Directives¶
RSpec Examples¶
describe 'Custom Directive' do
let(:processor) { PromptManager::DirectiveProcessor.new(storage: storage) }
let(:storage) { instance_double(PromptManager::Storage::Base) }
before do
processor.register_directive('test') do |args, context|
"processed: #{args}"
end
end
it 'processes custom directive' do
content = "//test hello world"
result = processor.process(content)
expect(result).to eq "processed: hello world"
end
it 'handles directive errors gracefully' do
processor.register_directive('error') { |args, context| raise 'test error' }
expect {
processor.process("//error test")
}.to raise_error(PromptManager::DirectiveProcessingError)
end
end
Best Practices¶
- Error Handling: Always handle errors gracefully in directive handlers
- Performance: Cache expensive operations in directive handlers
- Security: Validate and sanitize directive arguments
- Documentation: Document custom directive syntax and behavior
- Testing: Write comprehensive tests for custom directives
- Naming: Use descriptive names for custom directives
- Context: Use context parameter to access prompt rendering state