first commit
This commit is contained in:
196
tools/user_lookup_tool.py
Normal file
196
tools/user_lookup_tool.py
Normal file
@@ -0,0 +1,196 @@
|
||||
# --- START OF FILE user_lookup_tool.py ---
|
||||
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
from typing import Dict, Any
|
||||
|
||||
# --- Tool Definition (for LLM) ---
|
||||
TOOL_DEFINITION = {
|
||||
"name": "get_user_info",
|
||||
"description": "Look up information about Slack users from the cache file by searching across all available fields",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"search_term": {
|
||||
"type": "string",
|
||||
"description": "Term to search for - matches against any field in user records including ID, name, real name, display name, email, title, phone, etc."
|
||||
}
|
||||
},
|
||||
"required": ["search_term"]
|
||||
}
|
||||
}
|
||||
# --- End Tool Definition ---
|
||||
|
||||
|
||||
# --- Tool Implementation ---
|
||||
def get_user_info(**kwargs: Any) -> Dict[str, Any]:
|
||||
"""
|
||||
Retrieve user information from the user cache file by searching across all available fields,
|
||||
validating input arguments internally.
|
||||
|
||||
Args:
|
||||
**kwargs (Any): Keyword arguments matching the tool's input_schema properties
|
||||
(expects 'search_term').
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: A dictionary containing matched user information or an error message
|
||||
"""
|
||||
search_term = kwargs.get('search_term')
|
||||
|
||||
# --- Input Validation Moved Here ---
|
||||
# More forgiving search term validation
|
||||
# If search_term is None or empty after stripping, return error
|
||||
if search_term is None:
|
||||
logging.error("get_user_info validation failed: Missing 'search_term' argument.")
|
||||
return {
|
||||
"found": False,
|
||||
"error": "Missing required argument: 'search_term'."
|
||||
}
|
||||
|
||||
# Ensure search_term is a string and strip whitespace
|
||||
try:
|
||||
search_term = str(search_term).strip()
|
||||
except Exception as e:
|
||||
logging.error(f"get_user_info validation failed: Could not convert search_term to string: {e}")
|
||||
return {
|
||||
"found": False,
|
||||
"error": f"Invalid search_term format: {e}"
|
||||
}
|
||||
|
||||
if not search_term:
|
||||
logging.error("get_user_info validation failed: Empty 'search_term' provided.")
|
||||
return {
|
||||
"found": False,
|
||||
"error": "Empty search term provided after stripping whitespace."
|
||||
}
|
||||
# --- End Input Validation ---
|
||||
|
||||
try:
|
||||
logging.info(f"get_user_info: Attempting to find user with search term: {search_term}")
|
||||
|
||||
# Debug input received
|
||||
logging.info(f"Search term type: {type(search_term)}, value: '{search_term}'")
|
||||
|
||||
# Normalize search term
|
||||
search_term_lower = search_term.lower() # Use a different variable name
|
||||
|
||||
# Load the user cache
|
||||
try:
|
||||
# Specify encoding for broader compatibility
|
||||
with open('user_cache.json', 'r', encoding='utf-8') as f:
|
||||
user_cache = json.load(f)
|
||||
except FileNotFoundError:
|
||||
logging.error("User cache file 'user_cache.json' not found.")
|
||||
return {"found": False, "error": "User cache file not found."}
|
||||
except json.JSONDecodeError:
|
||||
logging.error("Invalid JSON in user cache file 'user_cache.json'.")
|
||||
return {"found": False, "error": "Invalid user cache format."}
|
||||
|
||||
# Search for matches across all users
|
||||
matches = []
|
||||
for user_id, user_data in user_cache.items():
|
||||
# Check if user_data is valid
|
||||
if not isinstance(user_data, dict):
|
||||
logging.warning(f"Skipping invalid user data entry for ID {user_id} in cache.")
|
||||
continue
|
||||
|
||||
# Flag to track if this user matches
|
||||
user_matches = False
|
||||
|
||||
# Check every field in the user data for matches
|
||||
for field_name, field_value in user_data.items():
|
||||
# Skip non-string fields or None values
|
||||
if field_value is None:
|
||||
continue
|
||||
|
||||
# Convert field value to string and check for match
|
||||
try:
|
||||
str_value = str(field_value).lower()
|
||||
if search_term_lower in str_value:
|
||||
user_matches = True
|
||||
break # Found a match in this user, no need to check other fields
|
||||
except Exception as e:
|
||||
# If any error in string conversion, just skip this field
|
||||
logging.debug(f"Could not convert field '{field_name}' to string for user {user_id}: {e}")
|
||||
continue
|
||||
|
||||
# If we found a match, add to our results
|
||||
if user_matches:
|
||||
# Create a clean user record with common fields
|
||||
user_record = {
|
||||
"id": user_data.get("id", user_id), # Use key as fallback ID
|
||||
"name": user_data.get("name", ""),
|
||||
"real_name": user_data.get("real_name", ""),
|
||||
"display_name": user_data.get("display_name", ""),
|
||||
"email": user_data.get("email", ""),
|
||||
}
|
||||
|
||||
# Add optional fields if they exist and are not None
|
||||
optional_fields = ["title", "phone", "first_name", "last_name", "cached_at", "status_text", "team"]
|
||||
for field in optional_fields:
|
||||
if field in user_data and user_data[field] is not None:
|
||||
user_record[field] = user_data[field]
|
||||
|
||||
matches.append(user_record)
|
||||
|
||||
# Return results
|
||||
if matches:
|
||||
logging.info(f"Found {len(matches)} match(es) for search term '{search_term}'.")
|
||||
return {
|
||||
"found": True,
|
||||
"match_count": len(matches),
|
||||
"matches": matches
|
||||
}
|
||||
else:
|
||||
logging.info(f"No users found matching '{search_term}'.")
|
||||
return {
|
||||
"found": False,
|
||||
"error": f"No users found matching '{search_term}'"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Unexpected error retrieving user info from cache: {e}", exc_info=True) # Added exc_info
|
||||
return {
|
||||
"found": False,
|
||||
"error": f"An unexpected error occurred while accessing user cache: {str(e)}"
|
||||
}
|
||||
# --- End Tool Implementation ---
|
||||
|
||||
# Example Usage
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
# Create a dummy cache file for testing if it doesn't exist
|
||||
dummy_cache_path = 'user_cache.json'
|
||||
if not os.path.exists(dummy_cache_path):
|
||||
print(f"Creating dummy {dummy_cache_path} for testing...")
|
||||
dummy_data = {
|
||||
"U123": {"id": "U123", "name": "john.doe", "real_name": "John Doe", "display_name": "Johnny", "email": "john.doe@example.com", "title": "Engineer"},
|
||||
"U456": {"id": "U456", "name": "jane.smith", "real_name": "Jane Smith", "display_name": "Janey", "email": "jane.smith@example.com", "title": "Manager"},
|
||||
"U789": {"id": "U789", "name": "test.user", "real_name": "Test User", "display_name": "", "email": "test@example.com", "phone": "555-1234"}
|
||||
}
|
||||
with open(dummy_cache_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(dummy_data, f, indent=2)
|
||||
|
||||
print("--- Testing get_user_info ---")
|
||||
# Example: Find users with 'john' in any field
|
||||
result1 = get_user_info(search_term="john")
|
||||
print(f"Result (search='john'): {json.dumps(result1, indent=2)}")
|
||||
|
||||
# Example: Find user by specific email
|
||||
result2 = get_user_info(search_term="jane.smith@example.com") # Use dummy email
|
||||
print(f"Result (search='jane.smith@example.com'): {json.dumps(result2, indent=2)}")
|
||||
|
||||
# Example: Search for empty string (should fail validation)
|
||||
result3 = get_user_info(search_term=" ")
|
||||
print(f"Result (search=' '): {json.dumps(result3, indent=2)}")
|
||||
|
||||
# Example: Search for None (should fail validation)
|
||||
result4 = get_user_info(search_term=None)
|
||||
print(f"Result (search=None): {json.dumps(result4, indent=2)}")
|
||||
|
||||
# Example: Search term not found
|
||||
result5 = get_user_info(search_term="NonExistentXYZ123")
|
||||
print(f"Result (search='NonExistentXYZ123'): {json.dumps(result5, indent=2)}")
|
||||
|
||||
# --- END OF FILE user_lookup_tool.py ---
|
||||
Reference in New Issue
Block a user