Skip to content

Commit 6cdc5b9

Browse files
authored
Devops agent v8 (#19)
* adding vllm and ollama support to agent * adding vllm and ollama support along with reasoning support to all agents
1 parent fd7118c commit 6cdc5b9

8 files changed

Lines changed: 58 additions & 81 deletions

File tree

devops_agent/cli.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ def default_provider() -> str:
2626
return "anthropic"
2727
elif os.environ.get("GEMINI_API_KEY"):
2828
return "google"
29+
elif os.environ.get("OLLAMA_API_KEY"):
30+
return "ollama"
31+
elif os.environ.get("VLLM_API_KEY"):
32+
return "vllm"
2933
else:
3034
# If nothing found, fallback and warn
3135
console.print("[bold yellow]⚠️ No API key found. Defaulting to OpenAI (if set later).[/bold yellow]")
@@ -47,8 +51,9 @@ def default_model() -> str:
4751
@click.option('--output', type=click.Path(), help='Output file path (optional)')
4852
@click.option('--format', type=click.Choice(['text', 'json', 'markdown']), default='text', help='Output format')
4953
@click.option('--interactive', '-i', is_flag=True, help='Run in interactive mode')
50-
@click.option('--debug_mode', help='Run all agents in debug mode, don\'t use in production')
51-
def run(log_file, provider, model, query, output, format, interactive, debug_mode):
54+
@click.option('--debug_mode', type=bool, help='Run all agents in debug mode, don\'t use in production')
55+
@click.option('--reasoning_enabled', type=bool, help='Run all agents in debug mode, don\'t use in production')
56+
def run(log_file, provider, model, query, output, format, interactive, debug_mode, reasoning_enabled):
5257
"""Run the DevOps agent with specified options"""
5358

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

62-
# Interactive mode
67+
# Interactive mode
6368
if interactive:
64-
run_interactive_mode(provider, model, output, format, debug_mode)
69+
run_interactive_mode(provider, model, output, format, debug_mode, reasoning_enabled)
6570
return
6671

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

99104
if query:
100-
process_query(provider, query, output, format, debug_mode)
105+
process_query(provider, query, output, format, debug_mode, reasoning_enabled)
101106

102107

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

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

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

157163

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

167173
try:
168-
response = execute_master_agent(provider=provider, model_str=model, user_query=query, debug_mode=debug_mode)
174+
response = execute_master_agent(provider=provider, model_str=model, user_query=query,
175+
debug_mode=debug_mode, reasoning=reasoning_enabled)
169176
console.print(Panel.fit(
170177
f"[bold yellow]Assistant:[/bold yellow] [dim]{response}[/dim]",
171178
border_style="yellow"

devops_agent/core/devops_agent.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
import asyncio
2-
import os
31
from textwrap import dedent
42

53
from agno.agent import Agent
6-
from agno.knowledge import Knowledge
7-
from agno.models.openai import OpenAIChat
8-
from agno.models.anthropic import Claude
9-
from agno.models.google.gemini import Gemini
10-
from agno.vectordb.qdrant import Qdrant
11-
from agno.knowledge.embedder.fastembed import FastEmbedEmbedder
12-
from qdrant_client.http.models import VectorParams, Distance
4+
from devops_agent.utils.model_provider import get_model
135
from rich.console import Console
146
from rich.panel import Panel
157

@@ -19,20 +11,13 @@
1911

2012
console = Console()
2113

22-
def execute_devops_agent(provider: str, model: str, debug_mode: bool = False) -> Agent:
14+
def execute_devops_agent(provider: str, model: str, debug_mode: bool = False, reasoning:bool=False) -> Agent:
2315
console.print(Panel.fit(
2416
"[bold cyan]DevOps Agent Invoking...[/bold cyan]",
2517
border_style="cyan"
2618
))
27-
llm_provider = provider.lower().strip()
28-
if llm_provider == 'openai':
29-
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
30-
elif llm_provider == 'anthropic':
31-
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
32-
elif llm_provider == 'google':
33-
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
34-
else:
35-
model = OpenAIChat(id=model), #default
19+
20+
model = get_model(provider=provider, model_str=model)
3621

3722
devops_assist = Agent(
3823
name="DevOps Agent",
@@ -53,6 +38,7 @@ def execute_devops_agent(provider: str, model: str, debug_mode: bool = False) ->
5338
stream_intermediate_steps=True,
5439
markdown=True,
5540
debug_mode=debug_mode,
41+
reasoning=reasoning
5642
)
5743

5844
return devops_assist
Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import os
21
from textwrap import dedent
32

43
from agno.agent import Agent
5-
from agno.models.openai import OpenAIChat
6-
from agno.models.anthropic import Claude
7-
from agno.models.google.gemini import Gemini
4+
from devops_agent.utils.model_provider import get_model
85
from rich.console import Console
96
from rich.panel import Panel
107

@@ -14,22 +11,14 @@
1411

1512
console = Console()
1613

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

1916
console.print(Panel.fit(
2017
"[bold cyan]Kubernetes Agent Invoking...[/bold cyan]",
2118
border_style="cyan"
2219
))
2320

24-
llm_provider = provider.lower().strip()
25-
if llm_provider == 'openai':
26-
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
27-
elif llm_provider == 'anthropic':
28-
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
29-
elif llm_provider == 'google':
30-
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
31-
else:
32-
model = OpenAIChat(id="gpt-5-mini"), # default
21+
model = get_model(provider=provider, model_str=model)
3322

3423
k8s_assist = Agent(
3524
name="Kubernetes Agent",
@@ -50,7 +39,8 @@ def execute_k8s_agent(provider: str, model:str, debug_mode: bool=False) -> Agent
5039
"""),
5140
stream_intermediate_steps=True,
5241
markdown=True,
53-
debug_mode=debug_mode
42+
debug_mode=debug_mode,
43+
reasoning=reasoning
5444
)
5545

5646
return k8s_assist

devops_agent/core/log_analysis_agent.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,20 @@
33

44
from agno.agent import Agent
55
from agno.media import File
6-
from agno.models.openai import OpenAIChat
7-
from agno.models.anthropic import Claude
8-
from agno.models.google.gemini import Gemini
6+
from devops_agent.utils.model_provider import get_model
97
from rich.console import Console
108
from rich.panel import Panel
119

1210
console = Console()
1311

14-
def execute_log_analysis_agent(provider: str, model: str, log_file: Path, debug_mode: bool= False) -> Agent:
12+
def execute_log_analysis_agent(provider: str, model: str, log_file: Path, debug_mode: bool= False,
13+
reasoning:bool=False) -> Agent:
1514
console.print(Panel.fit(
1615
"[bold cyan]Log Analysis Agent Invoking...[/bold cyan]",
1716
border_style="cyan"
1817
))
19-
llm_provider = provider.lower().strip()
20-
if llm_provider == 'openai':
21-
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
22-
elif llm_provider == 'anthropic':
23-
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
24-
elif llm_provider == 'google':
25-
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
26-
else:
27-
model = OpenAIChat(id=model), #default
18+
19+
model = get_model(provider=provider, model_str=model)
2820

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

4134
print("executing the log analysis")

devops_agent/core/master_agent.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,18 @@
5656
),
5757
)
5858

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

6364
devops_team = Team(
6465
name="Multi Cloud and Devops Team",
6566
model=model,
6667
members=[
67-
execute_devops_agent(provider=provider, model=model_str, debug_mode=debug_mode),
68-
execute_k8s_agent(provider=provider, model=model_str, debug_mode=debug_mode),
69-
execute_terraform_agent(provider=provider, model=model_str, debug_mode=debug_mode),
68+
execute_devops_agent(provider=provider, model=model_str, debug_mode=debug_mode, reasoning=reasoning),
69+
execute_k8s_agent(provider=provider, model=model_str, debug_mode=debug_mode, reasoning=reasoning),
70+
execute_terraform_agent(provider=provider, model=model_str, debug_mode=debug_mode, reasoning=reasoning),
7071
],
7172
instructions=[
7273
"You are a intelligent router that directs questions to the appropriate agent.",
Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,22 @@
1-
import asyncio
2-
import os
3-
41
from agno.agent import Agent
5-
from agno.models.openai import OpenAIChat
6-
from agno.models.anthropic import Claude
7-
from agno.models.google.gemini import Gemini
82
from rich.console import Console
93
from rich.panel import Panel
4+
from devops_agent.utils.model_provider import get_model
105

116
from devops_agent.utils.prompt_generator_from_poml import prompt_from_poml
127

138
terraform_prompt = prompt_from_poml('terraform.poml')
149

1510
console = Console()
1611

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

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

24-
llm_provider = provider.lower().strip()
25-
if llm_provider == 'openai':
26-
model = OpenAIChat(id=model, api_key=os.environ.get('OPENAI_API_KEY'))
27-
elif llm_provider == 'anthropic':
28-
model = Claude(id=model, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
29-
elif llm_provider == 'google':
30-
model = Gemini(id=model, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
31-
else:
32-
model = OpenAIChat(id=model), # default
19+
model = get_model(provider=provider, model_str=model)
3320

3421
terraform_assist = Agent(
3522
name="Terraform Agent",
@@ -39,7 +26,8 @@ def execute_terraform_agent(provider: str, model: str, debug_mode: bool=False) -
3926
instructions=terraform_prompt,
4027
stream_intermediate_steps=True,
4128
markdown=True,
42-
debug_mode=debug_mode
29+
debug_mode=debug_mode,
30+
reasoning=reasoning
4331
)
4432

4533
return terraform_assist

devops_agent/utils/model_provider.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
from agno.models.anthropic import Claude
22
from agno.models.google import Gemini
3-
from agno.models.openai import OpenAIChat
3+
from agno.models.openai import OpenAIChat, OpenAILike
4+
from agno.models.ollama import Ollama
45
from dotenv import load_dotenv, find_dotenv
56
import os
67

78
load_dotenv(find_dotenv())
89

910

10-
def get_model(provider: str, model_str: str):
11+
def get_model(provider: str, model_str: str, ollama_base_url: str = None, vllm_base_url: str = None, ):
1112
llm_provider = provider.lower().strip()
1213
if llm_provider == 'openai':
1314
model = OpenAIChat(id=model_str, api_key=os.environ.get('OPENAI_API_KEY'))
1415
elif llm_provider == 'anthropic':
1516
model = Claude(id=model_str, temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY'))
1617
elif llm_provider == 'google':
1718
model = Gemini(id=model_str, temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY'))
19+
elif llm_provider == 'ollama':
20+
if os.environ.get('OLLAMA_API_KEY') is not None:
21+
model = Ollama(id=model_str, host=ollama_base_url, api_key=os.environ.get('OLLAMA_API_KEY'))
22+
else:
23+
model = Ollama(id=model_str, host=ollama_base_url)
24+
elif llm_provider == 'vllm':
25+
if os.environ.get('VLLM_API_KEY') is not None:
26+
model = OpenAILike(id=model_str, base_url=vllm_base_url, api_key=os.environ.get('VLLM_API_KEY'))
27+
else:
28+
model = OpenAILike(id=model_str, base_url=vllm_base_url)
1829
else:
1930
model = OpenAIChat(id=model_str, api_key=os.environ.get('OPENAI_API_KEY')), # default
2031

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ rich>=13.0.0
1010
anthropic>=0.18.0
1111
openai>=2.1.0
1212
google-genai>=1.41.0
13+
ollama>=0.6.1
1314

1415
# File Processing
1516
pyyaml>=6.0

0 commit comments

Comments
 (0)