from agents import Agent, function_tool from retriever_tool import db from textwrap import dedent from agents import Tool from model import gemini_model, qwen_model @function_tool def unused_ports() -> str: """Get information about unused Ethernet interfaces across all network devices. This tool specifically queries for unused/available ports in the network infrastructure by filtering documents with 'Ethernet Interfaces Summary' headers and UNUSED interfaces. Only returns results from leaf switches (devices with 'LEAF' in their name). """ # Use metadata-based filtering instead of similarity search # Get all documents from the vectorstore all_docs_with_scores = db.similarity_search_with_score("", k=db.index.ntotal) # Filter documents by header metadata and device type target_header = "Ethernet Interfaces Summary" matching_docs = [] for doc, score in all_docs_with_scores: # Check if document has the target header section_title = doc.metadata.get('section_title', '') header_path = doc.metadata.get('header_path', '') device_name = doc.metadata.get('device_name', '') # Filter for: # 1. Documents with "Ethernet Interfaces Summary" in header path # 2. Documents from LEAF devices only # 3. Documents that contain UNUSED interfaces is_ethernet_summary = (target_header == section_title or target_header in header_path) is_leaf_device = 'LEAF' in device_name.upper() has_unused = 'UNUSED' in doc.page_content if is_ethernet_summary and is_leaf_device and has_unused: matching_docs.append((doc, score)) response = "" if not matching_docs: return "No unused interface information found in Ethernet Interfaces Summary sections of leaf devices." # Track devices and their unused interfaces device_unused = {} for doc, score in matching_docs: device_name = doc.metadata.get('device_name') source = doc.metadata.get('source', 'Unknown source') header_path = doc.metadata.get('header_path', 'No header path') section_title = doc.metadata.get('section_title', 'No section title') if device_name: # Count UNUSED interfaces in this chunk unused_count = doc.page_content.count('UNUSED') if unused_count > 0: if device_name not in device_unused: device_unused[device_name] = { 'total_unused': 0, 'sections': [], 'source': source } device_unused[device_name]['total_unused'] += unused_count device_unused[device_name]['sections'].append({ 'section': section_title, 'header_path': header_path, 'count': unused_count, 'score': score }) # Format the response with enhanced metadata if matching_docs: # Attach the actual sections containing UNUSED interfaces from each document for doc, score in matching_docs: device_name = doc.metadata.get('device_name', 'Unknown device') source = doc.metadata.get('source', 'Unknown source') section_title = doc.metadata.get('section_title', 'No section title') header_path = doc.metadata.get('header_path', 'No header path') response += f"---\n" response += f"Device: {device_name} (Source: {source})\n" response += f"Section: {section_title}\n" response += f"Path: {header_path}\n\n" # Extract and attach only the lines that actually contain UNUSED interfaces for line in doc.page_content.splitlines(): if 'UNUSED' in line: response += line + "\n" response += "\n" else: response += "No leaf devices with unused interfaces found in Ethernet Interfaces Summary sections." print(f"Retrieved {len(matching_docs)} filtered results from Ethernet Interfaces Summary sections on leaf devices") return response # Port recommendation specific instructions port_recommendation_instructions = dedent(""" You are an expert network assistant specialized in port and interface recommendations. Your role is to use the available tools to answer questions about port/interface recommendations for connecting new devices to the network infrastructure. Key responsibilities: - Port and interface are synonymous terms (users may use them interchangeably) - Always use the retrieve_network_information tool to find unused interface ports before making recommendations - Provide specific device names and port numbers in your recommendations - Be detailed and precise in your responses Port Recommendation Rules: 1. If not specified otherwise, always recommend TWO ports across different devices for redundancy 2. Recommend ports across devices that form a MLAG or LACP group 3. Leaf switches are in MLAG pairs: odd-numbered leaf (leaf01, leaf03, etc.) paired with even-numbered leaf (leaf02, leaf04, etc.) 4. Try to select the same interface port number across paired devices (e.g., if recommending port 25 on leaf01, also recommend port 25 on leaf02) 5. Include device names and specific port identifiers in your response 6. If user specifically requests single port or "without redundancy", recommend only one port 7. Only recommend ports that have the description "UNUSED". Response Format: - Always query for unused ports first using retrieve_network_information - Provide clear, actionable recommendations with device names and port numbers - Explain the reasoning behind your recommendations when relevant Examples: User: "I need an unused port" Response: After checking available ports, I recommend using Ethernet1/25 on leaf01 and Ethernet1/25 on leaf02 for redundancy. User: "I need an unused port without redundancy" Response: After checking available ports, I recommend using Ethernet1/26 on leaf01. User: "I need to dual connect a server to the network, what ports should I use?" Response: For dual-connecting a server, I recommend using Ethernet1/27 on leaf01 and Ethernet1/27 on leaf02, which will provide MLAG redundancy. User: "I need to connect two servers to the network, what ports should I use?" Response: For connecting two servers, I recommend using Ethernet1/28-29 on leaf01 and Ethernet1/28-29 on leaf02 for redundancy. """) # Create the specialized port recommendations agent port_recommendations_agent = Agent( name="port_recommendations_agent", instructions=port_recommendation_instructions, model=qwen_model, tools=[unused_ports], )