Forget everything you know about traditional content management. Forget clunky admin panels, endless forms, and the tedious cycle of coding, testing, and deploying even simple text changes. Forget the limitations of predefined actions and the development time sunk into building those restrictive interfaces.
Now, imagine a different reality. Imagine simply telling your web application what you want. “Change the hero banner text.” “Add a section about our new service.” “Make this button green.” Imagine using casual, everyday language – maybe even with a typo or two – and watching your application understand and execute your request instantly.
Mind-blowing? Maybe. But this future isn’t science fiction anymore. It’s here, and it’s powered by AI agents.
With the Enferno framework, integrating these agentic superpowers into your Flask application is surprisingly straightforward. We’ll show you how to add an AI-powered “Developer Agent” that lets you modify frontend templates using simple natural language commands – like having a mini-Cursor running right inside your app, ready to follow your instructions.
Prerequisites & Dependencies
To bring this agentic magic to life, you’ll primarily need:
- Enferno Framework: The foundation for our application.
- An Agent Library: We use
agno
(version1.2.6
or higher is recommended) for its simplicity in creating agents and integrating tools. - An LLM API Key: For example, an OpenAI API key if using models like GPT-4o. Make sure to export your OpenAI API key in your
.env
file:
<span>OPENAI_API_KEY</span><span>=</span>your-api-key-here<span>OPENAI_API_KEY</span><span>=</span>your-api-key-hereOPENAI_API_KEY=your-api-key-here
Enter fullscreen mode Exit fullscreen mode
- Key Dependencies: Ensure
agno>=1.2.6
andopenai>=1.12.0
(or your chosen LLM’s library) are included in yourrequirements.txt
.
The Vision: Beyond Traditional CMS
Traditional Content Management Systems offer predefined interfaces. While powerful, they can be rigid. Developer tasks like tweaking templates often involve manual code changes, context switching, and careful validation.
What if we could bridge this gap? What if you could instruct your application directly?
"Hey Enferno, change the homepage title to 'Welcome Agents!' and make it blue.""Hey Enferno, change the homepage title to 'Welcome Agents!' and make it blue.""Hey Enferno, change the homepage title to 'Welcome Agents!' and make it blue."
Enter fullscreen mode Exit fullscreen mode
This is the core idea: leveraging AI agents that understand your project’s structure and rules to perform tasks based on natural language instructions.
Meet the Enferno Developer Agent
We can implement a DeveloperAgent
within our Enferno application. This agent acts as an AI assistant specialized in understanding and modifying the project structure, particularly Jinja2 templates.
Key Concepts:
- AI Agent Core: Use a library (like
agno
) to manage the agent’s interaction with a Large Language Model (LLM), handle prompts, and process responses. - Tools for Action: Equip the agent with tools to interact with the application. For template modification,
FileTools
(scoped to thetemplates
directory for safety) allow the agent to read and write files. - Context-Aware Instructions: This is crucial. Initialize the agent with detailed instructions about the Enferno framework’s patterns (Vue/Jinja integration, Vuetify components). Dynamically loading project-specific rules (like
.cursor/rules/*.mdc
files) ensures the agent adheres to your coding standards. - CLI Integration: Expose the agent’s functionality via a clean Flask command-line interface using
click
for easy access.
Under the Hood: The Agentic Engine
So, how does this magic actually work? Let’s peek behind the curtain at the core components. Adding agentic capabilities requires surprisingly little boilerplate in Enferno.
1. The Brain: Defining the Agent (enferno/agents/developer.py
):
This class is the heart of our operation – the AI assistant ready to follow instructions. We equip it with:
- A powerful language model (like GPT-4o).
- Safely scoped tools (like
FileTools
restricted to thetemplates
directory). - Project-specific instructions and context (like your codebase rules loaded from
.cursor/rules
).
<span># enferno/agents/developer.py </span><span>import</span> <span>os</span><span>from</span> <span>pathlib</span> <span>import</span> <span>Path</span><span>from</span> <span>textwrap</span> <span>import</span> <span>dedent</span><span>from</span> <span>agno.agent</span> <span>import</span> <span>Agent</span> <span># Example using agno </span><span>from</span> <span>agno.models.openai</span> <span>import</span> <span>OpenAIChat</span><span>from</span> <span>agno.tools.file</span> <span>import</span> <span>FileTools</span><span>class</span> <span>DeveloperAgent</span><span>:</span><span>"""</span><span>An AI assistant specialized in development tasks.</span><span>"""</span><span>def</span> <span>__init__</span><span>(</span><span>self</span><span>):</span><span>current_dir</span> <span>=</span> <span>Path</span><span>(</span><span>__file__</span><span>).</span><span>parent</span><span>.</span><span>parent</span><span>templates_dir</span> <span>=</span> <span>current_dir</span> <span>/</span> <span>'</span><span>templates</span><span>'</span><span>rules_dir</span> <span>=</span> <span>Path</span><span>(</span><span>os</span><span>.</span><span>getcwd</span><span>())</span> <span>/</span> <span>'</span><span>.cursor</span><span>'</span> <span>/</span> <span>'</span><span>rules</span><span>'</span><span># ... (Rule loading logic to get combined_rules) ... </span> <span>combined_rules</span> <span>=</span> <span>'</span><span>\n</span><span>'</span><span>.</span><span>join</span><span>(</span><span>rules_content</span><span>.</span><span>values</span><span>())</span><span>self</span><span>.</span><span>agent</span> <span>=</span> <span>Agent</span><span>(</span><span>name</span><span>=</span><span>"</span><span>Enferno Developer</span><span>"</span><span>,</span><span>model</span><span>=</span><span>OpenAIChat</span><span>(</span><span>id</span><span>=</span><span>"</span><span>gpt-4o</span><span>"</span><span>),</span> <span># Use a powerful LLM </span> <span>tools</span><span>=</span><span>[</span><span>FileTools</span><span>(</span><span>base_dir</span><span>=</span><span>templates_dir</span><span>,</span> <span># Safely scoped </span> <span>save_files</span><span>=</span><span>True</span><span>,</span> <span>read_files</span><span>=</span><span>True</span><span>,</span> <span>list_files</span><span>=</span><span>True</span><span>)],</span><span>show_tool_calls</span><span>=</span><span>True</span><span>,</span><span>instructions</span><span>=</span><span>dedent</span><span>(</span><span>f</span><span>"""</span><span>\ </span><span> You are an expert Enferno framework developer... Follow Jinja2/Vue patterns... Use Vuetify components correctly... IMPORTANT - Follow these specific patterns: </span><span>{</span><span>combined_rules</span><span>}</span><span> </span><span>"""</span> <span>),</span> <span># Inject project rules </span> <span>markdown</span><span>=</span><span>True</span><span>)</span><span>def</span> <span>modify_template</span><span>(</span><span>self</span><span>,</span> <span>request</span><span>,</span> <span>template_path</span><span>=</span><span>"</span><span>index.html</span><span>"</span><span>,</span> <span>stream</span><span>=</span><span>True</span><span>):</span><span>"""</span><span>Modify a template based on the request.</span><span>"""</span><span>template_path_obj</span> <span>=</span> <span>Path</span><span>(</span><span>template_path</span><span>)</span><span># ... (Logic to read template, prompt agent, execute, verify) ... </span> <span>prompt</span> <span>=</span> <span>dedent</span><span>(</span><span>f</span><span>"""</span><span>\ </span><span> Please modify template: </span><span>{</span><span>template_path_obj</span><span>.</span><span>name</span><span>}</span><span> Request: </span><span>{</span><span>request</span><span>}</span><span> Perform these steps: 1. Read the file content. 2. Analyze the request and plan changes respecting structure. 3. Apply changes ONLY to text content or attributes like CSS classes. 4. Save the modified file. Be careful with Jinja/Vue syntax. </span><span>"""</span><span>)</span><span>response</span> <span>=</span> <span>self</span><span>.</span><span>agent</span><span>.</span><span>print_response</span><span>(</span><span>prompt</span><span>,</span> <span>stream</span><span>=</span><span>stream</span><span>)</span><span># ... (Add verification logic here if desired) ... </span> <span>return</span> <span>response</span><span># enferno/agents/developer.py </span><span>import</span> <span>os</span> <span>from</span> <span>pathlib</span> <span>import</span> <span>Path</span> <span>from</span> <span>textwrap</span> <span>import</span> <span>dedent</span> <span>from</span> <span>agno.agent</span> <span>import</span> <span>Agent</span> <span># Example using agno </span><span>from</span> <span>agno.models.openai</span> <span>import</span> <span>OpenAIChat</span> <span>from</span> <span>agno.tools.file</span> <span>import</span> <span>FileTools</span> <span>class</span> <span>DeveloperAgent</span><span>:</span> <span>"""</span><span>An AI assistant specialized in development tasks.</span><span>"""</span> <span>def</span> <span>__init__</span><span>(</span><span>self</span><span>):</span> <span>current_dir</span> <span>=</span> <span>Path</span><span>(</span><span>__file__</span><span>).</span><span>parent</span><span>.</span><span>parent</span> <span>templates_dir</span> <span>=</span> <span>current_dir</span> <span>/</span> <span>'</span><span>templates</span><span>'</span> <span>rules_dir</span> <span>=</span> <span>Path</span><span>(</span><span>os</span><span>.</span><span>getcwd</span><span>())</span> <span>/</span> <span>'</span><span>.cursor</span><span>'</span> <span>/</span> <span>'</span><span>rules</span><span>'</span> <span># ... (Rule loading logic to get combined_rules) ... </span> <span>combined_rules</span> <span>=</span> <span>'</span><span>\n</span><span>'</span><span>.</span><span>join</span><span>(</span><span>rules_content</span><span>.</span><span>values</span><span>())</span> <span>self</span><span>.</span><span>agent</span> <span>=</span> <span>Agent</span><span>(</span> <span>name</span><span>=</span><span>"</span><span>Enferno Developer</span><span>"</span><span>,</span> <span>model</span><span>=</span><span>OpenAIChat</span><span>(</span><span>id</span><span>=</span><span>"</span><span>gpt-4o</span><span>"</span><span>),</span> <span># Use a powerful LLM </span> <span>tools</span><span>=</span><span>[</span><span>FileTools</span><span>(</span> <span>base_dir</span><span>=</span><span>templates_dir</span><span>,</span> <span># Safely scoped </span> <span>save_files</span><span>=</span><span>True</span><span>,</span> <span>read_files</span><span>=</span><span>True</span><span>,</span> <span>list_files</span><span>=</span><span>True</span> <span>)],</span> <span>show_tool_calls</span><span>=</span><span>True</span><span>,</span> <span>instructions</span><span>=</span><span>dedent</span><span>(</span><span>f</span><span>"""</span><span>\ </span><span> You are an expert Enferno framework developer... Follow Jinja2/Vue patterns... Use Vuetify components correctly... IMPORTANT - Follow these specific patterns: </span><span>{</span><span>combined_rules</span><span>}</span><span> </span><span>"""</span> <span>),</span> <span># Inject project rules </span> <span>markdown</span><span>=</span><span>True</span> <span>)</span> <span>def</span> <span>modify_template</span><span>(</span><span>self</span><span>,</span> <span>request</span><span>,</span> <span>template_path</span><span>=</span><span>"</span><span>index.html</span><span>"</span><span>,</span> <span>stream</span><span>=</span><span>True</span><span>):</span> <span>"""</span><span>Modify a template based on the request.</span><span>"""</span> <span>template_path_obj</span> <span>=</span> <span>Path</span><span>(</span><span>template_path</span><span>)</span> <span># ... (Logic to read template, prompt agent, execute, verify) ... </span> <span>prompt</span> <span>=</span> <span>dedent</span><span>(</span><span>f</span><span>"""</span><span>\ </span><span> Please modify template: </span><span>{</span><span>template_path_obj</span><span>.</span><span>name</span><span>}</span><span> Request: </span><span>{</span><span>request</span><span>}</span><span> Perform these steps: 1. Read the file content. 2. Analyze the request and plan changes respecting structure. 3. Apply changes ONLY to text content or attributes like CSS classes. 4. Save the modified file. Be careful with Jinja/Vue syntax. </span><span>"""</span><span>)</span> <span>response</span> <span>=</span> <span>self</span><span>.</span><span>agent</span><span>.</span><span>print_response</span><span>(</span><span>prompt</span><span>,</span> <span>stream</span><span>=</span><span>stream</span><span>)</span> <span># ... (Add verification logic here if desired) ... </span> <span>return</span> <span>response</span># enferno/agents/developer.py import os from pathlib import Path from textwrap import dedent from agno.agent import Agent # Example using agno from agno.models.openai import OpenAIChat from agno.tools.file import FileTools class DeveloperAgent: """An AI assistant specialized in development tasks.""" def __init__(self): current_dir = Path(__file__).parent.parent templates_dir = current_dir / 'templates' rules_dir = Path(os.getcwd()) / '.cursor' / 'rules' # ... (Rule loading logic to get combined_rules) ... combined_rules = '\n'.join(rules_content.values()) self.agent = Agent( name="Enferno Developer", model=OpenAIChat(id="gpt-4o"), # Use a powerful LLM tools=[FileTools( base_dir=templates_dir, # Safely scoped save_files=True, read_files=True, list_files=True )], show_tool_calls=True, instructions=dedent(f"""\ You are an expert Enferno framework developer... Follow Jinja2/Vue patterns... Use Vuetify components correctly... IMPORTANT - Follow these specific patterns: {combined_rules} """ ), # Inject project rules markdown=True ) def modify_template(self, request, template_path="index.html", stream=True): """Modify a template based on the request.""" template_path_obj = Path(template_path) # ... (Logic to read template, prompt agent, execute, verify) ... prompt = dedent(f"""\ Please modify template: {template_path_obj.name} Request: {request} Perform these steps: 1. Read the file content. 2. Analyze the request and plan changes respecting structure. 3. Apply changes ONLY to text content or attributes like CSS classes. 4. Save the modified file. Be careful with Jinja/Vue syntax. """) response = self.agent.print_response(prompt, stream=stream) # ... (Add verification logic here if desired) ... return response
Enter fullscreen mode Exit fullscreen mode
2. The Interface: Creating the CLI Command (enferno/commands.py
):
This is how you talk to the agent. We create a simple flask agent template
command using Click. When run:
- It prompts you for your request if you don’t provide one directly.
- It spins up the
DeveloperAgent
. - It passes your request to the agent’s
modify_template
method. - (Crucially, Enferno automatically finds and registers this command group – no manual
app.py
wiring needed!)
<span># enferno/commands.py </span><span>import</span> <span>click</span><span>from</span> <span>flask.cli</span> <span>import</span> <span>with_appcontext</span><span>,</span> <span>AppGroup</span><span># Assuming your agent class is importable </span><span>from</span> <span>enferno.agents</span> <span>import</span> <span>DeveloperAgent</span><span># Create agent command group </span><span>agent_cli</span> <span>=</span> <span>AppGroup</span><span>(</span><span>'</span><span>agent</span><span>'</span><span>,</span> <span>help</span><span>=</span><span>'</span><span>AI-powered development tools</span><span>'</span><span>)</span><span>@agent_cli.command</span><span>(</span><span>'</span><span>template</span><span>'</span><span>)</span><span>@click.argument</span><span>(</span><span>'</span><span>request</span><span>'</span><span>,</span> <span>required</span><span>=</span><span>False</span><span>)</span><span>@click.option</span><span>(</span><span>'</span><span>--template-path</span><span>'</span><span>,</span> <span>default</span><span>=</span><span>'</span><span>index.html</span><span>'</span><span>,</span> <span>help</span><span>=</span><span>'</span><span>Path to the template file relative to templates/</span><span>'</span><span>)</span><span>@with_appcontext</span><span>def</span> <span>template_cmd</span><span>(</span><span>request</span><span>,</span> <span>template_path</span><span>):</span><span>"""</span><span>Modify a template using AI assistance (text/attributes).</span><span>"""</span><span>if</span> <span>not</span> <span>request</span><span>:</span><span>request</span> <span>=</span> <span>click</span><span>.</span><span>prompt</span><span>(</span><span>'</span><span>What changes would you like to make to the template?</span><span>'</span><span>)</span><span>try</span><span>:</span><span># Instantiate the agent </span> <span>agent</span> <span>=</span> <span>DeveloperAgent</span><span>()</span><span># Call the agent method </span> <span>agent</span><span>.</span><span>modify_template</span><span>(</span><span>request</span><span>,</span> <span>template_path</span><span>)</span><span>click</span><span>.</span><span>echo</span><span>(</span><span>f</span><span>"</span><span> Agent finished processing request for </span><span>'</span><span>{</span><span>template_path</span><span>}</span><span>'</span><span>. Check the file for changes.</span><span>"</span><span>)</span><span>except</span> <span>Exception</span> <span>as</span> <span>e</span><span>:</span><span>click</span><span>.</span><span>echo</span><span>(</span><span>f</span><span>"</span><span>Error processing agent request: </span><span>{</span><span>str</span><span>(</span><span>e</span><span>)</span><span>}</span><span>"</span><span>,</span> <span>err</span><span>=</span><span>True</span><span>)</span><span># enferno/commands.py </span><span>import</span> <span>click</span> <span>from</span> <span>flask.cli</span> <span>import</span> <span>with_appcontext</span><span>,</span> <span>AppGroup</span> <span># Assuming your agent class is importable </span><span>from</span> <span>enferno.agents</span> <span>import</span> <span>DeveloperAgent</span> <span># Create agent command group </span><span>agent_cli</span> <span>=</span> <span>AppGroup</span><span>(</span><span>'</span><span>agent</span><span>'</span><span>,</span> <span>help</span><span>=</span><span>'</span><span>AI-powered development tools</span><span>'</span><span>)</span> <span>@agent_cli.command</span><span>(</span><span>'</span><span>template</span><span>'</span><span>)</span> <span>@click.argument</span><span>(</span><span>'</span><span>request</span><span>'</span><span>,</span> <span>required</span><span>=</span><span>False</span><span>)</span> <span>@click.option</span><span>(</span><span>'</span><span>--template-path</span><span>'</span><span>,</span> <span>default</span><span>=</span><span>'</span><span>index.html</span><span>'</span><span>,</span> <span>help</span><span>=</span><span>'</span><span>Path to the template file relative to templates/</span><span>'</span><span>)</span> <span>@with_appcontext</span> <span>def</span> <span>template_cmd</span><span>(</span><span>request</span><span>,</span> <span>template_path</span><span>):</span> <span>"""</span><span>Modify a template using AI assistance (text/attributes).</span><span>"""</span> <span>if</span> <span>not</span> <span>request</span><span>:</span> <span>request</span> <span>=</span> <span>click</span><span>.</span><span>prompt</span><span>(</span><span>'</span><span>What changes would you like to make to the template?</span><span>'</span><span>)</span> <span>try</span><span>:</span> <span># Instantiate the agent </span> <span>agent</span> <span>=</span> <span>DeveloperAgent</span><span>()</span> <span># Call the agent method </span> <span>agent</span><span>.</span><span>modify_template</span><span>(</span><span>request</span><span>,</span> <span>template_path</span><span>)</span> <span>click</span><span>.</span><span>echo</span><span>(</span><span>f</span><span>"</span><span> Agent finished processing request for </span><span>'</span><span>{</span><span>template_path</span><span>}</span><span>'</span><span>. Check the file for changes.</span><span>"</span><span>)</span> <span>except</span> <span>Exception</span> <span>as</span> <span>e</span><span>:</span> <span>click</span><span>.</span><span>echo</span><span>(</span><span>f</span><span>"</span><span>Error processing agent request: </span><span>{</span><span>str</span><span>(</span><span>e</span><span>)</span><span>}</span><span>"</span><span>,</span> <span>err</span><span>=</span><span>True</span><span>)</span># enferno/commands.py import click from flask.cli import with_appcontext, AppGroup # Assuming your agent class is importable from enferno.agents import DeveloperAgent # Create agent command group agent_cli = AppGroup('agent', help='AI-powered development tools') @agent_cli.command('template') @click.argument('request', required=False) @click.option('--template-path', default='index.html', help='Path to the template file relative to templates/') @with_appcontext def template_cmd(request, template_path): """Modify a template using AI assistance (text/attributes).""" if not request: request = click.prompt('What changes would you like to make to the template?') try: # Instantiate the agent agent = DeveloperAgent() # Call the agent method agent.modify_template(request, template_path) click.echo(f" Agent finished processing request for '{template_path}'. Check the file for changes.") except Exception as e: click.echo(f"Error processing agent request: {str(e)}", err=True)
Enter fullscreen mode Exit fullscreen mode
(Note: Enferno automatically detects and registers click.Command
and click.Group
objects like agent_cli
defined in enferno/commands.py
, so no manual registration in app.py
is needed.)
Demo: Modifying Homepage Content via CLI
Let’s see it in action! Here’s our initial homepage:
Initial homepage before modifications
Now, let’s modify the content. Simply type:
flask agent templateflask agent templateflask agent template
Enter fullscreen mode Exit fullscreen mode
The command will prompt you:
What changes would you like to make to the template?What changes would you like to make to the template?What changes would you like to make to the template?
Enter fullscreen mode Exit fullscreen mode
You can then type your request:
Make the main card wider by adding a max-width class, then update the main title to 'The Great Monkey-Horse Adventure' and change the text below it to a fun story about 5 monkeys and a horse who go on an adventure together. Make it engaging and funny. Also, make the title text blue.Make the main card wider by adding a max-width class, then update the main title to 'The Great Monkey-Horse Adventure' and change the text below it to a fun story about 5 monkeys and a horse who go on an adventure together. Make it engaging and funny. Also, make the title text blue.Make the main card wider by adding a max-width class, then update the main title to 'The Great Monkey-Horse Adventure' and change the text below it to a fun story about 5 monkeys and a horse who go on an adventure together. Make it engaging and funny. Also, make the title text blue.
Enter fullscreen mode Exit fullscreen mode
The DeveloperAgent
processes your request and modifies the template. Here’s the result:
Homepage after applying the changes
Just like that, we’ve transformed our homepage into an engaging story using a natural language command!
Your In-App “Mini-Cursor”
This approach essentially embeds a specialized AI assistant within your application’s framework. It understands the context, follows project-specific rules, and uses tools safely. It’s like having a focused version of Cursor available directly via your application’s CLI, accelerating specific development and content management tasks.
The Future is Agentic
This is just the beginning. Imagine extending this concept:
- Agents for generating blog post drafts based on outlines.
- Agents for managing user roles or permissions via commands.
- Agents integrated into a web UI for non-developers to update content safely within predefined boundaries.
- Agents helping automate database interactions based on high-level descriptions.
The Enferno framework provides a flexible and accessible platform for experimenting with and building these next-generation, agentic web applications.
Get the Code
Explore the Enferno framework and its agentic potential. The code for this example can be found at:
https://github.com/level09/natcms.git (Note: This repo demonstrates the concept)
Let us know what you think! How would you improve this agent? What other agentic features would you like to see integrated into web frameworks?
P.S. Want more wild ideas about the future of web dev, AI, and maybe even robot pets? Follow me on Twitter: @level09!
原文链接:Build the Future: An AI-Powered, Natural Language CMS with Enferno
暂无评论内容