Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-27 07:41:42

0001 """
0002 Common utilities and tool discovery for MCP tools.
0003 """
0004 
0005 import logging
0006 from datetime import timedelta
0007 from django.utils import timezone
0008 from django.utils.dateparse import parse_datetime
0009 
0010 logger = logging.getLogger(__name__)
0011 
0012 
0013 def _parse_time(time_str):
0014     """Parse ISO datetime string, return None if invalid."""
0015     if not time_str:
0016         return None
0017     try:
0018         return parse_datetime(time_str)
0019     except (ValueError, TypeError):
0020         return None
0021 
0022 
0023 def _default_start_time(hours=24):
0024     """Return default start time (N hours ago)."""
0025     return timezone.now() - timedelta(hours=hours)
0026 
0027 
0028 def _get_username(username: str = None) -> str:
0029     """Validate and return the username. Must be provided by the caller."""
0030     if not username:
0031         raise RuntimeError("username parameter is required")
0032     return username
0033 
0034 
0035 def _monitor_url(path: str) -> str:
0036     """Build a full monitor URL from a path."""
0037     import os
0038     base = os.getenv('SWF_MONITOR_HTTP_URL', 'http://localhost:8000/swf-monitor')
0039     return f"{base.rstrip('/')}/{path.lstrip('/')}"
0040 
0041 
0042 def _get_testbed_config_path() -> tuple:
0043     """
0044     Get the testbed config file path.
0045 
0046     Returns:
0047         (Path, str): Tuple of (config_path, source) where source is
0048                      'SWF_TESTBED_CONFIG' or 'default'
0049     """
0050     import os
0051     from pathlib import Path
0052 
0053     swf_home = os.getenv('SWF_HOME', '')
0054     config_env = os.getenv('SWF_TESTBED_CONFIG')
0055 
0056     if config_env:
0057         # Env var can be absolute or relative to workflows/
0058         if os.path.isabs(config_env):
0059             return Path(config_env), 'SWF_TESTBED_CONFIG'
0060         else:
0061             return Path(swf_home) / 'swf-testbed' / 'workflows' / config_env, 'SWF_TESTBED_CONFIG'
0062     else:
0063         return Path(swf_home) / 'swf-testbed' / 'workflows' / 'testbed.toml', 'default'
0064 
0065 
0066 # -----------------------------------------------------------------------------
0067 # Tool Discovery
0068 # -----------------------------------------------------------------------------
0069 # IMPORTANT: When adding a new @mcp.tool(), you MUST also add it to the
0070 # hardcoded list below. This list is what LLMs see when discovering tools.
0071 #
0072 # Also update: server instructions in settings.py, docs/MCP.md
0073 # -----------------------------------------------------------------------------
0074 
0075 def get_available_tools_list() -> list:
0076     """
0077     Return the hardcoded list of all available MCP tools.
0078     Called by swf_list_available_tools in __init__.py.
0079     """
0080     return [
0081         {
0082             "name": "swf_list_available_tools",
0083             "description": "List all available MCP tools with descriptions",
0084             "parameters": [],
0085         },
0086         {
0087             "name": "swf_get_system_state",
0088             "description": "Get comprehensive system state: user context, agent manager, workflow runner, readiness, agents, executions",
0089             "parameters": ["username"],
0090         },
0091         {
0092             "name": "swf_list_agents",
0093             "description": "List registered agents. Excludes EXITED agents by default. Use status='EXITED' to see exited, status='all' to see all.",
0094             "parameters": ["namespace", "agent_type", "status", "execution_id", "start_time", "end_time"],
0095         },
0096         {
0097             "name": "swf_get_agent",
0098             "description": "Get detailed information about a specific agent",
0099             "parameters": ["name"],
0100         },
0101         {
0102             "name": "swf_list_namespaces",
0103             "description": "List all testbed namespaces (isolation boundaries for users)",
0104             "parameters": [],
0105         },
0106         {
0107             "name": "swf_get_namespace",
0108             "description": "Get namespace details including activity counts",
0109             "parameters": ["namespace", "start_time", "end_time"],
0110         },
0111         {
0112             "name": "swf_list_workflow_definitions",
0113             "description": "List available workflow definitions that can be executed",
0114             "parameters": ["workflow_type", "created_by"],
0115         },
0116         {
0117             "name": "swf_list_workflow_executions",
0118             "description": "List workflow executions. Use currently_running=True to see what's running now",
0119             "parameters": ["namespace", "status", "executed_by", "workflow_name", "currently_running", "start_time", "end_time"],
0120         },
0121         {
0122             "name": "swf_get_workflow_execution",
0123             "description": "Get detailed information about a specific workflow execution",
0124             "parameters": ["execution_id"],
0125         },
0126         {
0127             "name": "swf_list_messages",
0128             "description": "List workflow messages between agents for debugging",
0129             "parameters": ["namespace", "execution_id", "agent", "message_type", "start_time", "end_time"],
0130         },
0131         {
0132             "name": "swf_list_runs",
0133             "description": "List simulation runs with timing and STF file counts",
0134             "parameters": ["start_time", "end_time"],
0135         },
0136         {
0137             "name": "swf_get_run",
0138             "description": "Get detailed information about a specific run",
0139             "parameters": ["run_number"],
0140         },
0141         {
0142             "name": "swf_list_stf_files",
0143             "description": "List STF (Super Time Frame) files with filtering",
0144             "parameters": ["run_number", "status", "machine_state", "start_time", "end_time"],
0145         },
0146         {
0147             "name": "swf_get_stf_file",
0148             "description": "Get detailed information about a specific STF file",
0149             "parameters": ["file_id", "stf_filename"],
0150         },
0151         {
0152             "name": "swf_list_tf_slices",
0153             "description": "List TF slices for fast processing workflow",
0154             "parameters": ["run_number", "stf_filename", "tf_filename", "status", "assigned_worker", "start_time", "end_time"],
0155         },
0156         {
0157             "name": "swf_get_tf_slice",
0158             "description": "Get detailed information about a specific TF slice",
0159             "parameters": ["tf_filename", "slice_id"],
0160         },
0161         {
0162             "name": "swf_list_logs",
0163             "description": "List application log entries. Use level='ERROR' to find errors",
0164             "parameters": ["app_name", "instance_name", "execution_id", "level", "search", "start_time", "end_time"],
0165         },
0166         {
0167             "name": "swf_get_log_entry",
0168             "description": "Get full details of a specific log entry",
0169             "parameters": ["log_id"],
0170         },
0171         {
0172             "name": "swf_start_workflow",
0173             "description": "Start a workflow by sending command to DAQ Simulator agent",
0174             "parameters": ["workflow_name", "namespace", "config", "realtime", "duration",
0175                           "stf_count", "physics_period_count", "physics_period_duration", "stf_interval"],
0176         },
0177         {
0178             "name": "swf_stop_workflow",
0179             "description": "Stop a running workflow by sending stop command to agent",
0180             "parameters": ["execution_id"],
0181         },
0182         {
0183             "name": "swf_end_execution",
0184             "description": "Mark a workflow execution as terminated in database (no agent message)",
0185             "parameters": ["execution_id"],
0186         },
0187         {
0188             "name": "swf_kill_agent",
0189             "description": "Kill an agent process by sending SIGKILL to its PID. Sets status to EXITED.",
0190             "parameters": ["name"],
0191         },
0192         {
0193             "name": "swf_check_agent_manager",
0194             "description": "Check if user's agent manager daemon is alive (has recent heartbeat)",
0195             "parameters": ["username"],
0196         },
0197         {
0198             "name": "swf_start_user_testbed",
0199             "description": "Start user's testbed via their agent manager daemon",
0200             "parameters": ["username", "config_name"],
0201         },
0202         {
0203             "name": "swf_stop_user_testbed",
0204             "description": "Stop user's testbed via their agent manager daemon",
0205             "parameters": ["username"],
0206         },
0207         {
0208             "name": "swf_get_testbed_status",
0209             "description": "Get comprehensive testbed status: agent manager, namespace, workflow agents",
0210             "parameters": ["username"],
0211         },
0212         {
0213             "name": "swf_get_workflow_monitor",
0214             "description": "Get status and events for a workflow execution (aggregates messages/logs)",
0215             "parameters": ["execution_id"],
0216         },
0217         {
0218             "name": "swf_list_workflow_monitors",
0219             "description": "List recent workflow executions that can be monitored",
0220             "parameters": [],
0221         },
0222         {
0223             "name": "swf_send_message",
0224             "description": "Send a message to the monitoring stream (for testing, announcements, etc.)",
0225             "parameters": ["message", "message_type", "metadata"],
0226         },
0227         {
0228             "name": "swf_record_ai_memory",
0229             "description": "Record a dialogue exchange for AI memory persistence",
0230             "parameters": ["username", "session_id", "role", "content", "namespace", "project_path"],
0231         },
0232         {
0233             "name": "swf_get_ai_memory",
0234             "description": "Get recent dialogue history for session context",
0235             "parameters": ["username", "turns", "namespace"],
0236         },
0237         # PanDA Monitor tools
0238         {
0239             "name": "panda_list_jobs",
0240             "description": "List PanDA jobs from ePIC production DB with summary stats. Cursor-based pagination via before_id.",
0241             "parameters": ["days", "status", "username", "site", "taskid", "reqid", "limit", "before_id"],
0242         },
0243         {
0244             "name": "panda_diagnose_jobs",
0245             "description": "Diagnose failed/faulty PanDA jobs with full error details (7 error components). Cursor-based pagination via before_id.",
0246             "parameters": ["days", "username", "site", "taskid", "reqid", "error_component", "limit", "before_id"],
0247         },
0248         {
0249             "name": "panda_list_tasks",
0250             "description": "List JEDI tasks from ePIC production DB with summary stats. Tasks are higher-level than jobs. Cursor-based pagination via before_id.",
0251             "parameters": ["days", "status", "username", "taskname", "reqid", "workinggroup", "taskid", "processingtype", "limit", "before_id"],
0252         },
0253         {
0254             "name": "panda_error_summary",
0255             "description": "Aggregate error summary across failed PanDA jobs, ranked by frequency. Shows most common errors with affected tasks, users, sites.",
0256             "parameters": ["days", "username", "site", "taskid", "error_source", "limit"],
0257         },
0258         {
0259             "name": "panda_get_activity",
0260             "description": "Pre-digested PanDA activity overview — aggregate counts only, no individual records. Use first to answer 'What is PanDA doing?'",
0261             "parameters": ["days", "username", "site", "workinggroup"],
0262         },
0263         {
0264             "name": "panda_list_queues",
0265             "description": "List PanDA compute queues with configuration summary. Filter by VO (e.g. 'eic'), status, state, or name search.",
0266             "parameters": ["vo", "status", "state", "search"],
0267         },
0268         {
0269             "name": "panda_get_queue",
0270             "description": "Full configuration for a single PanDA queue — container options, storage, CE endpoints, resource limits.",
0271             "parameters": ["panda_queue"],
0272         },
0273         {
0274             "name": "panda_resource_usage",
0275             "description": "Aggregate core-hours for finished jobs — allocated (facility charge) vs used (actual CPU). Breakdowns by site and user.",
0276             "parameters": ["days", "site", "username", "taskid"],
0277         },
0278         {
0279             "name": "panda_study_job",
0280             "description": "Deep study of a single PanDA job — full record, files, errors, log URLs, harvester info, parent task context.",
0281             "parameters": ["pandaid"],
0282         },
0283         {
0284             "name": "panda_harvester_workers",
0285             "description": "Live Harvester pilot/worker counts across EIC queues — running, submitted, finished by site.",
0286             "parameters": ["site", "hours"],
0287         },
0288         # PCS (Physics Configuration System) tools
0289         {
0290             "name": "pcs_list_tags",
0291             "description": "List PCS (Physics Configuration System) tags — production task configurations for MC campaigns. Filter by type (p/e/s/r), category, status, creator, or text.",
0292             "parameters": ["tag_type", "category", "status", "creator", "search", "limit"],
0293         },
0294         {
0295             "name": "pcs_get_tag",
0296             "description": "Get full details of a single PCS tag by label (e.g. 'p1001', 'e3', 'r1').",
0297             "parameters": ["tag_label"],
0298         },
0299         {
0300             "name": "pcs_search_tags",
0301             "description": "Search PCS tags by keyword in label, description, or parameter values (e.g. 'photoproduction', 'eAu', 'pythia8').",
0302             "parameters": ["query", "tag_type", "limit"],
0303         },
0304     ]