Systematic Template Rendering Issues Across Pipeline Tools
Problem Statement
Multiple pipelines are experiencing consistent issues with template placeholders not being properly rendered in outputs. This affects:
- research_basic.yaml - Final reports contain
{{variable}} placeholders
- research_advanced_tools.yaml - Outputs are entirely placeholder text
- filesystem operations - Template variables not resolved at runtime
- Model prompts - Step results not accessible in templates
Current commit: a62433e
Current Approach Analysis
1. Template Rendering Lifecycle
The current system uses Jinja2 templating at multiple stages:
Pipeline YAML → Compiler (compile-time) → Runtime Execution → Output
Key Issues:
- Compile-time vs Runtime: Templates in YAML are rendered at compile time, but step results only exist at runtime
- Context Propagation: Step results are stored but not consistently made available to subsequent steps
- Tool-specific Handling: Each tool handles templates differently, leading to inconsistencies
2. Current Implementation Points
a) Compiler Level (src/orchestrator/compiler/)
# Templates are rendered during YAML compilation
compiled_pipeline = compiler.compile(pipeline_yaml)
- Templates like
{{topic}} are resolved here
- But
{{step_id.result}} references don't exist yet
b) Execution Level (src/orchestrator/executor/)
# Step results stored in state
state.set_step_result(step_id, result)
- Results are stored but not automatically injected into template contexts
c) Tool Level (src/orchestrator/tools/)
- Each tool independently handles parameter templating
- No standardized approach for accessing previous step results
3. Specific Problem Areas
-
Filesystem Write Operations
- Content parameter contains unrendered templates
- Example:
"{{compile_report.result}}" written literally to files
-
Model Prompts
- Templates reference future steps at compile time
- Example:
{{extract_key_points.result}} undefined during compilation
-
Report Generation
- Complex nested templates fail to render
- Example:
{{ search_topic.results[0].title }} when results is empty
Proposed Solution: Infrastructure-Level Template Management
Design Principles
- Lazy Evaluation: Defer template rendering until execution time when all context is available
- Unified Context: Maintain a global template context accessible to all tools
- Graceful Defaults: Handle missing values without breaking execution
- Type Safety: Preserve object structures for complex template expressions
Implementation Plan
Phase 1: Core Infrastructure Changes
- Create Template Manager (
src/orchestrator/core/template_manager.py)
class TemplateManager:
def __init__(self):
self.env = Environment(undefined=ChainableUndefined)
self.context = {}
def register_context(self, key: str, value: Any):
"""Register values for template resolution"""
self.context[key] = value
def render(self, template: str, additional_context: dict = None):
"""Render template with full context"""
context = {**self.context, **(additional_context or {})}
return self.env.from_string(template).render(context)
def defer_render(self, template: str) -> DeferredTemplate:
"""Return a deferred template for lazy evaluation"""
return DeferredTemplate(template, self)
- Modify Executor (
src/orchestrator/executor/step_executor.py)
# Before executing each step
template_manager.register_context('previous_results', state.get_all_results())
template_manager.register_context(step_id, result)
# Render parameters just-in-time
rendered_params = template_manager.render_dict(step.parameters)
- Update Tool Base Class (
src/orchestrator/tools/base.py)
class Tool:
def execute(self, template_manager: TemplateManager, **kwargs):
# Automatically render all string parameters
rendered_kwargs = self._render_parameters(kwargs, template_manager)
return self._execute_impl(**rendered_kwargs)
Phase 2: Tool Integration
-
Standardize Parameter Rendering
- All tools inherit automatic template rendering
- Special handling for nested structures (lists, dicts)
-
Context Injection Points
- Pipeline parameters
- Step results
- Execution metadata
- Environment variables
-
Error Handling
- Undefined variable warnings
- Fallback to original template if rendering fails
- Debug mode to show template resolution steps
Phase 3: Testing and Validation
-
Unit Tests
- Test template rendering with missing context
- Test nested template expressions
- Test deferred evaluation
-
Integration Tests
- Run all existing pytests
- Verify no regression in functionality
-
Pipeline Validation
- Re-run all verified pipelines:
- research_minimal.yaml
- research_basic.yaml
- research_advanced_tools.yaml
- auto_tags_demo.yaml
- control_flow/*.yaml
Success Criteria
-
No Placeholder Text in Outputs
- All
{{variable}} expressions resolved
- No template syntax in final outputs
-
Backward Compatibility
- All existing tests pass
- All verified pipelines produce same/better outputs
-
Developer Experience
- Clear error messages for undefined variables
- Debug mode showing template resolution
- Documentation for template best practices
-
Performance
- Minimal overhead from deferred rendering
- Efficient context propagation
Migration Strategy
- Phase 1: Implement core infrastructure (non-breaking)
- Phase 2: Update tools to use new system with fallback
- Phase 3: Migrate pipelines to leverage new features
- Phase 4: Deprecate old template handling
Example Usage After Implementation
# Templates "just work" without special handling
steps:
- id: search
tool: web-search
parameters:
query: "{{topic}}" # Pipeline parameter
- id: analyze
action: generate_text
parameters:
# Step results automatically available
prompt: "Analyze: {{search.results}}"
- id: save
tool: filesystem
parameters:
# Complex expressions work
content: "{{analyze.result | markdown_format}}"
path: "output/{{topic | slugify}}.md"
Risks and Mitigations
-
Risk: Breaking existing pipelines
- Mitigation: Comprehensive testing, gradual rollout
-
Risk: Performance degradation
- Mitigation: Benchmark before/after, optimize hot paths
-
Risk: Complex debugging
- Mitigation: Enhanced logging, template preview tools
Timeline Estimate
- Week 1: Core infrastructure implementation
- Week 2: Tool integration and testing
- Week 3: Pipeline validation and documentation
- Week 4: Bug fixes and optimization
This systematic approach will eliminate the recurring template issues and make the system more robust for future development.
Systematic Template Rendering Issues Across Pipeline Tools
Problem Statement
Multiple pipelines are experiencing consistent issues with template placeholders not being properly rendered in outputs. This affects:
{{variable}}placeholdersCurrent commit: a62433e
Current Approach Analysis
1. Template Rendering Lifecycle
The current system uses Jinja2 templating at multiple stages:
Key Issues:
2. Current Implementation Points
a) Compiler Level (
src/orchestrator/compiler/){{topic}}are resolved here{{step_id.result}}references don't exist yetb) Execution Level (
src/orchestrator/executor/)c) Tool Level (
src/orchestrator/tools/)3. Specific Problem Areas
Filesystem Write Operations
"{{compile_report.result}}"written literally to filesModel Prompts
{{extract_key_points.result}}undefined during compilationReport Generation
{{ search_topic.results[0].title }}when results is emptyProposed Solution: Infrastructure-Level Template Management
Design Principles
Implementation Plan
Phase 1: Core Infrastructure Changes
src/orchestrator/core/template_manager.py)src/orchestrator/executor/step_executor.py)src/orchestrator/tools/base.py)Phase 2: Tool Integration
Standardize Parameter Rendering
Context Injection Points
Error Handling
Phase 3: Testing and Validation
Unit Tests
Integration Tests
Pipeline Validation
Success Criteria
No Placeholder Text in Outputs
{{variable}}expressions resolvedBackward Compatibility
Developer Experience
Performance
Migration Strategy
Example Usage After Implementation
Risks and Mitigations
Risk: Breaking existing pipelines
Risk: Performance degradation
Risk: Complex debugging
Timeline Estimate
This systematic approach will eliminate the recurring template issues and make the system more robust for future development.