158 lines
5.3 KiB
Gherkin
158 lines
5.3 KiB
Gherkin
Feature: YAML Template Engine with Jinja2 Support
|
|
As a developer using CleverAgents
|
|
I want to use Jinja2 templates directly in YAML files
|
|
So that I can create dynamic configurations without multiline strings
|
|
|
|
Background:
|
|
Given the YAML template engine is initialized
|
|
|
|
Scenario: Process YAML with inline Jinja2 loops
|
|
Given I have a YAML string with inline Jinja2 templates:
|
|
"""
|
|
config:
|
|
name: {{ project_name }}
|
|
version: {{ version }}
|
|
|
|
agents:
|
|
{% for i in range(num_agents) %}
|
|
agent_{{ i }}:
|
|
type: llm
|
|
config:
|
|
model: {% if i == 0 %}gpt-4{% else %}gpt-3.5-turbo{% endif %}
|
|
temperature: {{ 0.5 + i * 0.1 }}
|
|
system_prompt: Agent {{ i }} is ready
|
|
{% endfor %}
|
|
"""
|
|
And I have a YAML template context:
|
|
| key | value |
|
|
| project_name| TestProject |
|
|
| version | 1.0 |
|
|
| num_agents | 3 |
|
|
When I process the YAML with the template engine
|
|
Then the result should contain a "config" section with name "TestProject"
|
|
And the result should contain 3 agents named "agent_0", "agent_1", "agent_2"
|
|
And agent "agent_0" should have model "gpt-4"
|
|
And agent "agent_1" should have model "gpt-3.5-turbo"
|
|
|
|
Scenario: Process YAML with conditional blocks
|
|
Given I have a YAML string with conditional Jinja2 templates:
|
|
"""
|
|
agents:
|
|
base_agent:
|
|
type: llm
|
|
config:
|
|
model: gpt-3.5-turbo
|
|
|
|
{% if enable_supervisor %}
|
|
supervisor:
|
|
type: llm
|
|
config:
|
|
model: gpt-4
|
|
temperature: 0.3
|
|
system_prompt: I supervise {{ num_agents }} agents
|
|
{% endif %}
|
|
"""
|
|
And I have a YAML template context:
|
|
| key | value |
|
|
| enable_supervisor | true |
|
|
| num_agents | 5 |
|
|
When I process the YAML with the template engine
|
|
Then the result should contain an agent named "supervisor"
|
|
And agent "supervisor" should have system_prompt "I supervise 5 agents"
|
|
|
|
Scenario: Process nested structures with Jinja2
|
|
Given I have a YAML string with nested Jinja2 templates:
|
|
"""
|
|
teams:
|
|
{% for team in teams %}
|
|
{{ team.name }}:
|
|
lead: {{ team.lead }}
|
|
members:
|
|
{% for member in team.members %}
|
|
- name: {{ member.name }}
|
|
role: {{ member.role }}
|
|
skills:
|
|
{% for skill in member.skills %}
|
|
- {{ skill }}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
"""
|
|
And I have a complex template context with teams data
|
|
When I process the YAML with the template engine
|
|
Then the result should contain teams "backend" and "frontend"
|
|
And team "backend" should have lead "Alice"
|
|
And team "backend" should have 2 members
|
|
|
|
Scenario: Deferred template rendering
|
|
Given I have a YAML string with Jinja2 templates:
|
|
"""
|
|
template:
|
|
type: composite
|
|
components:
|
|
{% for i in range(team_size) %}
|
|
worker_{{ i }}:
|
|
type: agent
|
|
config:
|
|
id: {{ i }}
|
|
name: Worker {{ i + 1 }}
|
|
{% endfor %}
|
|
"""
|
|
When I load the YAML without context for deferred rendering
|
|
Then the template should be stored for later rendering
|
|
When I render the stored template with context:
|
|
| key | value |
|
|
| team_size | 3 |
|
|
Then the rendered result should contain 3 workers
|
|
|
|
Scenario: Complex Jinja2 expressions and filters
|
|
Given I have a YAML string with complex Jinja2 expressions:
|
|
"""
|
|
analysis:
|
|
data_points: {{ data | length }}
|
|
average: {{ (data | sum(attribute='value')) / (data | length) }}
|
|
above_threshold: {{ data | selectattr('value', '>', threshold) | list | length }}
|
|
|
|
summary:
|
|
{% for item in data | sort(attribute='value', reverse=True) %}
|
|
- name: {{ item.name }}
|
|
value: {{ item.value }}
|
|
status: {% if item.value > threshold %}high{% elif item.value > threshold * 0.5 %}medium{% else %}low{% endif %}
|
|
{% endfor %}
|
|
"""
|
|
And I have a template context with data array
|
|
When I process the YAML with the template engine
|
|
Then the analysis data_points should be 4
|
|
And the analysis average should be 60.25
|
|
And the analysis above_threshold should be 2
|
|
And the first summary item should have status "high"
|
|
|
|
Scenario: Handle empty template blocks gracefully
|
|
Given I have a YAML string with empty loops:
|
|
"""
|
|
items:
|
|
{% for item in items %}
|
|
- {{ item }}
|
|
{% endfor %}
|
|
static: value
|
|
"""
|
|
And I have a YAML template context:
|
|
| key | value |
|
|
| items | [] |
|
|
When I process the YAML with the template engine
|
|
Then the result should contain "items.static" with value "value"
|
|
|
|
Scenario: Support Unicode and special characters
|
|
Given I have a YAML string with Unicode content:
|
|
"""
|
|
messages:
|
|
{% for msg in messages %}
|
|
- text: {{ msg.text }}
|
|
emoji: {{ msg.emoji }}
|
|
{% endfor %}
|
|
"""
|
|
And I have a template context with Unicode messages
|
|
When I process the YAML with the template engine
|
|
Then the result should contain 3 messages
|
|
And the second message text should be "Ça va?"
|