diff --git a/devops_agent/cli.py b/devops_agent/cli.py index 3876605..3ee4798 100644 --- a/devops_agent/cli.py +++ b/devops_agent/cli.py @@ -2,7 +2,7 @@ from rich.console import Console from rich.panel import Panel from rich.prompt import Prompt -from devops_agent.core.devops_agent import execute_devops_agent +from devops_agent.core.master_agent import execute_master_agent console = Console() @@ -90,7 +90,7 @@ def run_interactive_mode(provider: str, output: str = None, format: str = 'text' )) try: - response = execute_devops_agent(provider=provider, user_query=user_input) + response = execute_master_agent(provider=provider, user_query=user_input) console.print(f"\n[bold cyan]Assistant:[/bold cyan]\n{response}") # Save to output file if specified @@ -118,7 +118,7 @@ def process_query(provider: str, query: str, output: str = None, format: str = ' )) try: - response = execute_devops_agent(provider=provider, user_query=query) + response = execute_master_agent(provider=provider, user_query=query) console.print(f"\n[bold cyan]Assistant:[/bold cyan]\n{response}") if output: diff --git a/devops_agent/core/devops_agent.py b/devops_agent/core/devops_agent.py index 9ec991b..baae1fe 100644 --- a/devops_agent/core/devops_agent.py +++ b/devops_agent/core/devops_agent.py @@ -9,24 +9,32 @@ from agno.vectordb.qdrant import Qdrant from agno.knowledge.embedder.fastembed import FastEmbedEmbedder from qdrant_client.http.models import VectorParams, Distance +from rich.console import Console +from rich.panel import Panel from devops_agent.utils.prompt_generator_from_poml import prompt_from_poml from qdrant_client.qdrant_client import QdrantClient devops_prompt = prompt_from_poml('devops.poml') -qclient = QdrantClient(url=os.environ.get('QDRANT_URL'), api_key=os.environ.get('QDRANT_API_KEY')) -if not qclient.collection_exists("devops-memory"): - qclient.create_collection(collection_name="devops-memory", vectors_config=VectorParams(size=768, distance=Distance.COSINE)) +# qclient = QdrantClient(url=os.environ.get('QDRANT_URL'), api_key=os.environ.get('QDRANT_API_KEY')) +# if not qclient.collection_exists("devops-memory"): +# qclient.create_collection(collection_name="devops-memory", vectors_config=VectorParams(size=768, distance=Distance.COSINE)) +# +# vector_db = Qdrant(collection="devops-memory", url=os.environ.get('QDRANT_URL'), +# api_key=os.environ.get('QDRANT_API_KEY'), +# embedder=FastEmbedEmbedder(id="snowflake/snowflake-arctic-embed-m")) +# +# # Create knowledge base +# knowledge = Knowledge(vector_db=vector_db) -vector_db = Qdrant(collection="devops-memory", url=os.environ.get('QDRANT_URL'), - api_key=os.environ.get('QDRANT_API_KEY'), - embedder=FastEmbedEmbedder(id="snowflake/snowflake-arctic-embed-m")) +console = Console() -# Create knowledge base -knowledge = Knowledge(vector_db=vector_db) - -def execute_devops_agent(provider: str, user_query: str) -> str: +def execute_devops_agent(provider: str, user_query: str = None) -> Agent: + console.print(Panel.fit( + "[bold cyan]DevOps Agent Executing...[/bold cyan]", + border_style="cyan" + )) llm_provider = provider.lower().strip() if llm_provider == 'openai': model = OpenAIChat(id="gpt-5-mini", api_key=os.environ.get('OPENAI_API_KEY')) @@ -38,21 +46,23 @@ def execute_devops_agent(provider: str, user_query: str) -> str: model = OpenAIChat(id="gpt-5-mini"), #default devops_assist = Agent( - name="DevOps Assist", + name="DevOps Agent", model=model, description="You help answer questions about the devops domain.", instructions=devops_prompt, - knowledge=knowledge, - stream_intermediate_steps=True, - add_knowledge_to_context=True, - add_datetime_to_context=True, - add_session_summary_to_context=True, + # knowledge=knowledge, + # stream_intermediate_steps=True, + # add_knowledge_to_context=True, + # add_datetime_to_context=True, + # add_session_summary_to_context=True, markdown=True, ) - response = devops_assist.run(user_query, stream_intermediate_steps=True, retry=3) + # response = devops_assist.run(user_query, stream_intermediate_steps=True, retry=3) + # + # asyncio.run( + # knowledge.add_content_async(text_content=response.content, metadata={"agent_id": response.agent_id, "session_id": response.session_id}) + # ) + # return response.content - asyncio.run( - knowledge.add_content_async(text_content=response.content, metadata={"agent_id": response.agent_id, "session_id": response.session_id}) - ) - return response.content \ No newline at end of file + return devops_assist \ No newline at end of file diff --git a/devops_agent/core/kubernetes_agent.py b/devops_agent/core/kubernetes_agent.py index e69de29..60f4fed 100644 --- a/devops_agent/core/kubernetes_agent.py +++ b/devops_agent/core/kubernetes_agent.py @@ -0,0 +1,72 @@ +import asyncio +import os + +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 rich.console import Console +from rich.panel import Panel + +from devops_agent.utils.prompt_generator_from_poml import prompt_from_poml +from qdrant_client.qdrant_client import QdrantClient + +k8s_prompt = prompt_from_poml('kubernetes.poml') + +# qclient = QdrantClient(url=os.environ.get('QDRANT_URL'), api_key=os.environ.get('QDRANT_API_KEY')) +# if not qclient.collection_exists("devops-memory"): +# qclient.create_collection(collection_name="devops-memory", +# vectors_config=VectorParams(size=768, distance=Distance.COSINE)) +# +# vector_db = Qdrant(collection="devops-memory", url=os.environ.get('QDRANT_URL'), +# api_key=os.environ.get('QDRANT_API_KEY'), +# embedder=FastEmbedEmbedder(id="snowflake/snowflake-arctic-embed-m")) +# +# # Create knowledge base +# knowledge = Knowledge(vector_db=vector_db) + +console = Console() + +def execute_k8s_agent(provider: str, user_query: str = None) -> Agent: + + console.print(Panel.fit( + "[bold cyan]Kubernetes Agent Executing...[/bold cyan]", + border_style="cyan" + )) + + llm_provider = provider.lower().strip() + if llm_provider == 'openai': + model = OpenAIChat(id="gpt-5-mini", api_key=os.environ.get('OPENAI_API_KEY')) + elif llm_provider == 'anthropic': + model = Claude(id="claude-sonnet-4-5-20250929", temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY')) + elif llm_provider == 'google': + model = Gemini(id="gemini-2.5-flash", temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY')) + else: + model = OpenAIChat(id="gpt-5-mini"), # default + + k8s_assist = Agent( + name="Kubernetes Agent", + model=model, + description="You help answer questions about the kubernetes domain of any infrastructure like Azure(AKS), AWS(EKS), and GCP(GKS)", + instructions=k8s_prompt, + # knowledge=knowledge, + # stream_intermediate_steps=True, + # add_knowledge_to_context=True, + # add_datetime_to_context=True, + # add_session_summary_to_context=True, + markdown=True, + ) + + # response = k8s_assist.run(user_query, stream_intermediate_steps=True, retry=3) + # + # asyncio.run( + # knowledge.add_content_async(text_content=response.content, + # metadata={"agent_id": response.agent_id, "session_id": response.session_id}) + # ) + # return response.content + + return k8s_assist diff --git a/devops_agent/core/master_agent.py b/devops_agent/core/master_agent.py new file mode 100644 index 0000000..7f3ac26 --- /dev/null +++ b/devops_agent/core/master_agent.py @@ -0,0 +1,74 @@ +import asyncio +import os + +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.team import Team +from agno.vectordb.qdrant import Qdrant +from agno.knowledge.embedder.fastembed import FastEmbedEmbedder +from qdrant_client import QdrantClient +from qdrant_client.http.models import VectorParams, Distance + +from devops_agent.core.devops_agent import execute_devops_agent +from devops_agent.core.kubernetes_agent import execute_k8s_agent + +qclient = QdrantClient(url=os.environ.get('QDRANT_URL'), api_key=os.environ.get('QDRANT_API_KEY')) +if not qclient.collection_exists("devops-memory"): + qclient.create_collection(collection_name="devops-memory", + vectors_config=VectorParams(size=768, distance=Distance.COSINE)) + +vector_db = Qdrant(collection="devops-memory", url=os.environ.get('QDRANT_URL'), + api_key=os.environ.get('QDRANT_API_KEY'), + embedder=FastEmbedEmbedder(id="snowflake/snowflake-arctic-embed-m")) + +# Create knowledge base +knowledge = Knowledge(vector_db=vector_db) + + +def execute_master_agent(provider: str, user_query: str) -> str: + llm_provider = provider.lower().strip() + if llm_provider == 'openai': + model = OpenAIChat(id="gpt-5-mini", api_key=os.environ.get('OPENAI_API_KEY')) + elif llm_provider == 'anthropic': + model = Claude(id="claude-sonnet-4-5-20250929", temperature=0.6, api_key=os.environ.get('ANTHROPIC_API_KEY')) + elif llm_provider == 'google': + model = Gemini(id="gemini-2.5-flash", temperature=0.6, api_key=os.environ.get('GEMINI_API_KEY')) + else: + model = OpenAIChat(id="gpt-5-mini"), # default + + devops_team = Team( + name="Multi Cloud and Devops Team", + model=model, + respond_directly=True, + members=[ + execute_devops_agent(provider=provider), + execute_k8s_agent(provider=provider), + ], + markdown=True, + instructions=[ + "You are a intelligent router that directs questions to the appropriate agent.", + "If the user asks in a non devops or k8s question whose agent is not a team member, respond in English with:", + "'I can only answer in the following technologies: Devops & Kubernetes Architecture on Multiple clouds. Please ask your question in one of these technologies.'", + "Always check the technology or domain of the user's input before routing to an agent.", + "For unsupported technologies like coding, flowcharts, analytics etc respond in English with the above message.", + ], + knowledge=knowledge, + determine_input_for_members=True, + stream_intermediate_steps=True, + add_knowledge_to_context=True, + add_datetime_to_context=True, + add_session_summary_to_context=True, + show_members_responses=True, + ) + + response = devops_team.run(user_query, stream_intermediate_steps=True, retry=3) + + # saved the response to knowledge in async mode + asyncio.run( + knowledge.add_content_async(text_content=f"question: {user_query}, Assistant: {response.content}", + metadata={"agent_id": response.team_id, "session_id": response.session_id}) + ) + + return response.content