Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions devops_agent/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def default_provider() -> str:
return "anthropic"
elif os.environ.get("GEMINI_API_KEY"):
return "google"
elif os.environ.get("OLLAMA_API_KEY"):
return "ollama"
elif os.environ.get("VLLM_API_KEY"):
return "vllm"
else:
# If nothing found, fallback and warn
console.print("[bold yellow]⚠️ No API key found. Defaulting to OpenAI (if set later).[/bold yellow]")
Expand All @@ -47,8 +51,9 @@ def default_model() -> str:
@click.option('--output', type=click.Path(), help='Output file path (optional)')
@click.option('--format', type=click.Choice(['text', 'json', 'markdown']), default='text', help='Output format')
@click.option('--interactive', '-i', is_flag=True, help='Run in interactive mode')
@click.option('--debug_mode', help='Run all agents in debug mode, don\'t use in production')
def run(log_file, provider, model, query, output, format, interactive, debug_mode):
@click.option('--debug_mode', type=bool, help='Run all agents in debug mode, don\'t use in production')
@click.option('--reasoning_enabled', type=bool, help='Run all agents in debug mode, don\'t use in production')
def run(log_file, provider, model, query, output, format, interactive, debug_mode, reasoning_enabled):
"""Run the DevOps agent with specified options"""

if not provider:
Expand All @@ -59,9 +64,9 @@ def run(log_file, provider, model, query, output, format, interactive, debug_mod
console.print("[yellow]No model specified, defaulting to gpt-4o[/yellow]")
provider = default_model()

# Interactive mode
# Interactive mode
if interactive:
run_interactive_mode(provider, model, output, format, debug_mode)
run_interactive_mode(provider, model, output, format, debug_mode, reasoning_enabled)
return

# Single query mode (original behavior)
Expand All @@ -83,7 +88,7 @@ def run(log_file, provider, model, query, output, format, interactive, debug_mod
try:
file_path = Path(__file__).parent.joinpath(log_file)
response = execute_log_analysis_agent(provider=provider, model=model, log_file=file_path,
debug_mode=debug_mode)
debug_mode=debug_mode, reasoning=reasoning_enabled)
console.print(Panel.fit(
f"[bold yellow]Assistant:[/bold yellow] [dim]{response}[/dim]",
border_style="yellow"
Expand All @@ -97,10 +102,11 @@ def run(log_file, provider, model, query, output, format, interactive, debug_mod
console.print(f"\n[red]Error:[/red] {str(e)}")

if query:
process_query(provider, query, output, format, debug_mode)
process_query(provider, query, output, format, debug_mode, reasoning_enabled)


def run_interactive_mode(provider: str, model: str, output: str = None, format: str = 'text', debug_mode: bool = False):
def run_interactive_mode(provider: str, model: str, output: str = None, format: str = 'text',
debug_mode: bool = False, reasoning_enabled: bool = False):
"""Run the agent in interactive mode with continuous conversation"""

console.print(Panel.fit(
Expand Down Expand Up @@ -133,7 +139,7 @@ def run_interactive_mode(provider: str, model: str, output: str = None, format:

try:
response = execute_master_agent(provider=provider, model_str=model, user_query=user_input,
debug_mode=debug_mode)
debug_mode=debug_mode, reasoning=reasoning_enabled)
console.print(Panel.fit(
f"[bold yellow]Assistant:[/bold yellow] [dim]{response}[/dim]",
border_style="yellow"
Expand All @@ -156,7 +162,7 @@ def run_interactive_mode(provider: str, model: str, output: str = None, format:


def process_query(provider: str, model: str, query: str, output: str = None, format: str = 'text',
debug_mode: bool = False):
debug_mode: bool = False, reasoning_enabled: bool = False):
"""Process a single query"""
console.print(f"[yellow]Processing query:[/yellow] {query}")
console.print(Panel.fit(
Expand All @@ -165,7 +171,8 @@ def process_query(provider: str, model: str, query: str, output: str = None, for
))

try:
response = execute_master_agent(provider=provider, model_str=model, user_query=query, debug_mode=debug_mode)
response = execute_master_agent(provider=provider, model_str=model, user_query=query,
debug_mode=debug_mode, reasoning=reasoning_enabled)
console.print(Panel.fit(
f"[bold yellow]Assistant:[/bold yellow] [dim]{response}[/dim]",
border_style="yellow"
Expand Down
24 changes: 5 additions & 19 deletions devops_agent/core/devops_agent.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import asyncio
import os
from textwrap import dedent

from agno.agent import Agent
from agno.knowledge import Knowledge
from agno.models.openai import OpenAIChat
from agno.models.anthropic import Claude
from agno.models.google.gemini import Gemini
from agno.vectordb.qdrant import Qdrant
from agno.knowledge.embedder.fastembed import FastEmbedEmbedder
from qdrant_client.http.models import VectorParams, Distance
from devops_agent.utils.model_provider import get_model
from rich.console import Console
from rich.panel import Panel

Expand All @@ -19,20 +11,13 @@

console = Console()

def execute_devops_agent(provider: str, model: str, debug_mode: bool = False) -> Agent:
def execute_devops_agent(provider: str, model: str, debug_mode: bool = False, reasoning:bool=False) -> Agent:
console.print(Panel.fit(
"[bold cyan]DevOps Agent Invoking...[/bold cyan]",
border_style="cyan"
))
llm_provider = provider.lower().strip()
if llm_provider == 'openai':
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
elif llm_provider == 'anthropic':
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
elif llm_provider == 'google':
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
else:
model = OpenAIChat(id=model), #default

model = get_model(provider=provider, model_str=model)

devops_assist = Agent(
name="DevOps Agent",
Expand All @@ -53,6 +38,7 @@ def execute_devops_agent(provider: str, model: str, debug_mode: bool = False) ->
stream_intermediate_steps=True,
markdown=True,
debug_mode=debug_mode,
reasoning=reasoning
)

return devops_assist
20 changes: 5 additions & 15 deletions devops_agent/core/kubernetes_agent.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import os
from textwrap import dedent

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.models.anthropic import Claude
from agno.models.google.gemini import Gemini
from devops_agent.utils.model_provider import get_model
from rich.console import Console
from rich.panel import Panel

Expand All @@ -14,22 +11,14 @@

console = Console()

def execute_k8s_agent(provider: str, model:str, debug_mode: bool=False) -> Agent:
def execute_k8s_agent(provider: str, model:str, debug_mode: bool=False, reasoning:bool=False) -> Agent:

console.print(Panel.fit(
"[bold cyan]Kubernetes Agent Invoking...[/bold cyan]",
border_style="cyan"
))

llm_provider = provider.lower().strip()
if llm_provider == 'openai':
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
elif llm_provider == 'anthropic':
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
elif llm_provider == 'google':
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
else:
model = OpenAIChat(id="gpt-5-mini"), # default
model = get_model(provider=provider, model_str=model)

k8s_assist = Agent(
name="Kubernetes Agent",
Expand All @@ -50,7 +39,8 @@ def execute_k8s_agent(provider: str, model:str, debug_mode: bool=False) -> Agent
"""),
stream_intermediate_steps=True,
markdown=True,
debug_mode=debug_mode
debug_mode=debug_mode,
reasoning=reasoning
)

return k8s_assist
21 changes: 7 additions & 14 deletions devops_agent/core/log_analysis_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,20 @@

from agno.agent import Agent
from agno.media import File
from agno.models.openai import OpenAIChat
from agno.models.anthropic import Claude
from agno.models.google.gemini import Gemini
from devops_agent.utils.model_provider import get_model
from rich.console import Console
from rich.panel import Panel

console = Console()

def execute_log_analysis_agent(provider: str, model: str, log_file: Path, debug_mode: bool= False) -> Agent:
def execute_log_analysis_agent(provider: str, model: str, log_file: Path, debug_mode: bool= False,
reasoning:bool=False) -> Agent:
console.print(Panel.fit(
"[bold cyan]Log Analysis Agent Invoking...[/bold cyan]",
border_style="cyan"
))
llm_provider = provider.lower().strip()
if llm_provider == 'openai':
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
elif llm_provider == 'anthropic':
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
elif llm_provider == 'google':
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
else:
model = OpenAIChat(id=model), #default

model = get_model(provider=provider, model_str=model)

file_analysis_agent = Agent(
name="LogFile Analysis Agent",
Expand All @@ -35,7 +27,8 @@ def execute_log_analysis_agent(provider: str, model: str, log_file: Path, debug_
"You are an AI agent that can analyze log files.",
"You are given a log file and you need to analyse and give detailed answer to the question from the user.",
],
debug_mode=debug_mode
debug_mode=debug_mode,
reasoning=reasoning
)

print("executing the log analysis")
Expand Down
9 changes: 5 additions & 4 deletions devops_agent/core/master_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,18 @@
),
)

def execute_master_agent(provider: str, model_str: str, user_query: str = None, debug_mode: bool=False) -> str:
def execute_master_agent(provider: str, model_str: str, user_query: str = None, debug_mode: bool=False,
reasoning:bool=False) -> str:
# handle model provider uniquely at single place
model = get_model(provider=provider, model_str=model_str)

devops_team = Team(
name="Multi Cloud and Devops Team",
model=model,
members=[
execute_devops_agent(provider=provider, model=model_str, debug_mode=debug_mode),
execute_k8s_agent(provider=provider, model=model_str, debug_mode=debug_mode),
execute_terraform_agent(provider=provider, model=model_str, debug_mode=debug_mode),
execute_devops_agent(provider=provider, model=model_str, debug_mode=debug_mode, reasoning=reasoning),
execute_k8s_agent(provider=provider, model=model_str, debug_mode=debug_mode, reasoning=reasoning),
execute_terraform_agent(provider=provider, model=model_str, debug_mode=debug_mode, reasoning=reasoning),
],
instructions=[
"You are a intelligent router that directs questions to the appropriate agent.",
Expand Down
22 changes: 5 additions & 17 deletions devops_agent/core/terraform_agent.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,22 @@
import asyncio
import os

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.models.anthropic import Claude
from agno.models.google.gemini import Gemini
from rich.console import Console
from rich.panel import Panel
from devops_agent.utils.model_provider import get_model

from devops_agent.utils.prompt_generator_from_poml import prompt_from_poml

terraform_prompt = prompt_from_poml('terraform.poml')

console = Console()

def execute_terraform_agent(provider: str, model: str, debug_mode: bool=False) -> Agent:

def execute_terraform_agent(provider: str, model: str, debug_mode: bool = False, reasoning: bool = False) -> Agent:
console.print(Panel.fit(
"[bold cyan]Terraform Agent Invoking...[/bold cyan]",
border_style="cyan"
))

llm_provider = provider.lower().strip()
if llm_provider == 'openai':
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
elif llm_provider == 'anthropic':
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
elif llm_provider == 'google':
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
else:
model = OpenAIChat(id=model), # default
model = get_model(provider=provider, model_str=model)

terraform_assist = Agent(
name="Terraform Agent",
Expand All @@ -39,7 +26,8 @@ def execute_terraform_agent(provider: str, model: str, debug_mode: bool=False) -
instructions=terraform_prompt,
stream_intermediate_steps=True,
markdown=True,
debug_mode=debug_mode
debug_mode=debug_mode,
reasoning=reasoning
)

return terraform_assist
15 changes: 13 additions & 2 deletions devops_agent/utils/model_provider.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
from agno.models.anthropic import Claude
from agno.models.google import Gemini
from agno.models.openai import OpenAIChat
from agno.models.openai import OpenAIChat, OpenAILike
from agno.models.ollama import Ollama
from dotenv import load_dotenv, find_dotenv
import os

load_dotenv(find_dotenv())


def get_model(provider: str, model_str: str):
def get_model(provider: str, model_str: str, ollama_base_url: str = None, vllm_base_url: str = None, ):
llm_provider = provider.lower().strip()
if llm_provider == 'openai':
model = OpenAIChat(id=model_str, api_key=os.environ.get('OPENAI_API_KEY'))
elif llm_provider == 'anthropic':
model = Claude(id=model_str, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
elif llm_provider == 'google':
model = Gemini(id=model_str, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
elif llm_provider == 'ollama':
if os.environ.get('OLLAMA_API_KEY') is not None:
model = Ollama(id=model_str, host=ollama_base_url, api_key=os.environ.get('OLLAMA_API_KEY'))
else:
model = Ollama(id=model_str, host=ollama_base_url)
elif llm_provider == 'vllm':
if os.environ.get('VLLM_API_KEY') is not None:
model = OpenAILike(id=model_str, base_url=vllm_base_url, api_key=os.environ.get('VLLM_API_KEY'))
else:
model = OpenAILike(id=model_str, base_url=vllm_base_url)
else:
model = OpenAIChat(id=model_str, api_key=os.environ.get('OPENAI_API_KEY')), # default

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ rich>=13.0.0
anthropic>=0.18.0
openai>=2.1.0
google-genai>=1.41.0
ollama>=0.6.1

# File Processing
pyyaml>=6.0
Expand Down