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
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
0068
0069
0070
0071
0072
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
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
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 ]