@@ -2112,12 +2112,7 @@ def get_action_details(action_type: str) -> dict:
21122112 if not action_type or not action_type .strip ():
21132113 return {"error" : "Action type cannot be empty" }
21142114
2115- result = {
2116- "action_type" : action_type ,
2117- "goal" : {},
2118- "result" : {},
2119- "feedback" : {}
2120- }
2115+ result = {"action_type" : action_type , "goal" : {}, "result" : {}, "feedback" : {}}
21212116
21222117 # Get goal, result, and feedback details in a single WebSocket context
21232118 with ws_manager :
@@ -2131,7 +2126,12 @@ def get_action_details(action_type: str) -> dict:
21312126 }
21322127
21332128 goal_response = ws_manager .request (goal_message )
2134- if goal_response and isinstance (goal_response , dict ) and "values" in goal_response and "error" not in goal_response :
2129+ if (
2130+ goal_response
2131+ and isinstance (goal_response , dict )
2132+ and "values" in goal_response
2133+ and "error" not in goal_response
2134+ ):
21352135 typedefs = goal_response ["values" ].get ("typedefs" , [])
21362136 if typedefs :
21372137 for typedef in typedefs :
@@ -2141,24 +2141,24 @@ def get_action_details(action_type: str) -> dict:
21412141 examples = typedef .get ("examples" , [])
21422142 const_names = typedef .get ("constnames" , [])
21432143 const_values = typedef .get ("constvalues" , [])
2144-
2144+
21452145 fields = {}
21462146 field_details = {}
21472147 for i , (name , ftype ) in enumerate (zip (field_names , field_types )):
21482148 fields [name ] = ftype
21492149 field_details [name ] = {
21502150 "type" : ftype ,
21512151 "array_length" : field_array_len [i ] if i < len (field_array_len ) else - 1 ,
2152- "example" : examples [i ] if i < len (examples ) else None
2152+ "example" : examples [i ] if i < len (examples ) else None ,
21532153 }
2154-
2154+
21552155 result ["goal" ] = {
2156- "fields" : fields ,
2156+ "fields" : fields ,
21572157 "field_count" : len (fields ),
21582158 "field_details" : field_details ,
21592159 "message_type" : typedef .get ("type" , "" ),
21602160 "examples" : examples ,
2161- "constants" : dict (zip (const_names , const_values )) if const_names else {}
2161+ "constants" : dict (zip (const_names , const_values )) if const_names else {},
21622162 }
21632163
21642164 # Get result details using action-specific service
@@ -2171,7 +2171,12 @@ def get_action_details(action_type: str) -> dict:
21712171 }
21722172
21732173 result_response = ws_manager .request (result_message )
2174- if result_response and isinstance (result_response , dict ) and "values" in result_response and "error" not in result_response :
2174+ if (
2175+ result_response
2176+ and isinstance (result_response , dict )
2177+ and "values" in result_response
2178+ and "error" not in result_response
2179+ ):
21752180 typedefs = result_response ["values" ].get ("typedefs" , [])
21762181 if typedefs :
21772182 for typedef in typedefs :
@@ -2181,24 +2186,24 @@ def get_action_details(action_type: str) -> dict:
21812186 examples = typedef .get ("examples" , [])
21822187 const_names = typedef .get ("constnames" , [])
21832188 const_values = typedef .get ("constvalues" , [])
2184-
2189+
21852190 fields = {}
21862191 field_details = {}
21872192 for i , (name , ftype ) in enumerate (zip (field_names , field_types )):
21882193 fields [name ] = ftype
21892194 field_details [name ] = {
21902195 "type" : ftype ,
21912196 "array_length" : field_array_len [i ] if i < len (field_array_len ) else - 1 ,
2192- "example" : examples [i ] if i < len (examples ) else None
2197+ "example" : examples [i ] if i < len (examples ) else None ,
21932198 }
2194-
2199+
21952200 result ["result" ] = {
2196- "fields" : fields ,
2201+ "fields" : fields ,
21972202 "field_count" : len (fields ),
21982203 "field_details" : field_details ,
21992204 "message_type" : typedef .get ("type" , "" ),
22002205 "examples" : examples ,
2201- "constants" : dict (zip (const_names , const_values )) if const_names else {}
2206+ "constants" : dict (zip (const_names , const_values )) if const_names else {},
22022207 }
22032208
22042209 # Get feedback details using action-specific service
@@ -2211,7 +2216,12 @@ def get_action_details(action_type: str) -> dict:
22112216 }
22122217
22132218 feedback_response = ws_manager .request (feedback_message )
2214- if feedback_response and isinstance (feedback_response , dict ) and "values" in feedback_response and "error" not in feedback_response :
2219+ if (
2220+ feedback_response
2221+ and isinstance (feedback_response , dict )
2222+ and "values" in feedback_response
2223+ and "error" not in feedback_response
2224+ ):
22152225 typedefs = feedback_response ["values" ].get ("typedefs" , [])
22162226 if typedefs :
22172227 for typedef in typedefs :
@@ -2221,24 +2231,24 @@ def get_action_details(action_type: str) -> dict:
22212231 examples = typedef .get ("examples" , [])
22222232 const_names = typedef .get ("constnames" , [])
22232233 const_values = typedef .get ("constvalues" , [])
2224-
2234+
22252235 fields = {}
22262236 field_details = {}
22272237 for i , (name , ftype ) in enumerate (zip (field_names , field_types )):
22282238 fields [name ] = ftype
22292239 field_details [name ] = {
22302240 "type" : ftype ,
22312241 "array_length" : field_array_len [i ] if i < len (field_array_len ) else - 1 ,
2232- "example" : examples [i ] if i < len (examples ) else None
2242+ "example" : examples [i ] if i < len (examples ) else None ,
22332243 }
2234-
2244+
22352245 result ["feedback" ] = {
2236- "fields" : fields ,
2246+ "fields" : fields ,
22372247 "field_count" : len (fields ),
22382248 "field_details" : field_details ,
22392249 "message_type" : typedef .get ("type" , "" ),
22402250 "examples" : examples ,
2241- "constants" : dict (zip (const_names , const_values )) if const_names else {}
2251+ "constants" : dict (zip (const_names , const_values )) if const_names else {},
22422252 }
22432253
22442254 # Check if we got any data
@@ -2248,7 +2258,6 @@ def get_action_details(action_type: str) -> dict:
22482258 return result
22492259
22502260
2251-
22522261@mcp .tool (
22532262 description = (
22542263 "Get action status for a specific action name. Works only with ROS 2.\n "
@@ -2271,13 +2280,13 @@ def get_action_status(action_name: str) -> dict:
22712280 return {"error" : "Action name cannot be empty" }
22722281
22732282 # Ensure action name starts with /
2274- if not action_name .startswith ('/' ):
2283+ if not action_name .startswith ("/" ):
22752284 action_name = f"/{ action_name } "
2276-
2285+
22772286 # Try to get action status by subscribing to the status topic
22782287 status_topic = f"{ action_name } /_action/status"
22792288 status_msg_type = "action_msgs/msg/GoalStatusArray"
2280-
2289+
22812290 try :
22822291 # Subscribe to action status topic
22832292 with ws_manager :
@@ -2287,15 +2296,15 @@ def get_action_status(action_name: str) -> dict:
22872296 "type" : status_msg_type ,
22882297 "id" : f"get_action_status_{ action_name .replace ('/' , '_' )} " ,
22892298 }
2290-
2299+
22912300 send_error = ws_manager .send (message )
22922301 if send_error :
22932302 return {
22942303 "action_name" : action_name ,
22952304 "success" : False ,
22962305 "error" : f"Failed to subscribe to status topic: { send_error } " ,
22972306 }
2298-
2307+
22992308 # Wait for status message
23002309 response = ws_manager .receive (timeout = 3.0 )
23012310 if not response :
@@ -2304,49 +2313,58 @@ def get_action_status(action_name: str) -> dict:
23042313 "success" : False ,
23052314 "error" : "No response from action status topic" ,
23062315 }
2307-
2316+
23082317 response_data = json .loads (response )
2309-
2318+
23102319 if response_data .get ("op" ) == "status" and response_data .get ("level" ) == "error" :
2311- return {"error" : f"Action status error: { response_data .get ('msg' , 'Unknown error' )} " }
2312-
2320+ return {
2321+ "error" : f"Action status error: { response_data .get ('msg' , 'Unknown error' )} "
2322+ }
2323+
23132324 if "msg" not in response_data or "status_list" not in response_data ["msg" ]:
23142325 return {
23152326 "action_name" : action_name ,
23162327 "success" : True ,
23172328 "active_goals" : [],
23182329 "goal_count" : 0 ,
2319- "note" : f"No active goals found for action { action_name } "
2330+ "note" : f"No active goals found for action { action_name } " ,
23202331 }
2321-
2332+
23222333 status_list = response_data ["msg" ]["status_list" ]
23232334 status_map = {
2324- 0 : "STATUS_UNKNOWN" , 1 : "STATUS_ACCEPTED" , 2 : "STATUS_EXECUTING" ,
2325- 3 : "STATUS_CANCELING" , 4 : "STATUS_SUCCEEDED" , 5 : "STATUS_CANCELED" , 6 : "STATUS_ABORTED"
2335+ 0 : "STATUS_UNKNOWN" ,
2336+ 1 : "STATUS_ACCEPTED" ,
2337+ 2 : "STATUS_EXECUTING" ,
2338+ 3 : "STATUS_CANCELING" ,
2339+ 4 : "STATUS_SUCCEEDED" ,
2340+ 5 : "STATUS_CANCELED" ,
2341+ 6 : "STATUS_ABORTED" ,
23262342 }
2327-
2343+
23282344 active_goals = []
23292345 for status_item in status_list :
23302346 goal_info = status_item .get ("goal_info" , {})
23312347 goal_id = goal_info .get ("goal_id" , {}).get ("uuid" , "unknown" )
23322348 status = status_item .get ("status" , - 1 )
23332349 stamp = goal_info .get ("stamp" , {})
2334-
2335- active_goals .append ({
2336- "goal_id" : goal_id ,
2337- "status" : status ,
2338- "status_text" : status_map .get (status , "UNKNOWN" ),
2339- "timestamp" : f"{ stamp .get ('sec' , 0 )} .{ stamp .get ('nanosec' , 0 )} "
2340- })
2341-
2350+
2351+ active_goals .append (
2352+ {
2353+ "goal_id" : goal_id ,
2354+ "status" : status ,
2355+ "status_text" : status_map .get (status , "UNKNOWN" ),
2356+ "timestamp" : f"{ stamp .get ('sec' , 0 )} .{ stamp .get ('nanosec' , 0 )} " ,
2357+ }
2358+ )
2359+
23422360 return {
23432361 "action_name" : action_name ,
23442362 "success" : True ,
23452363 "active_goals" : active_goals ,
23462364 "goal_count" : len (active_goals ),
2347- "note" : f"Found { len (active_goals )} active goal(s) for action { action_name } "
2365+ "note" : f"Found { len (active_goals )} active goal(s) for action { action_name } " ,
23482366 }
2349-
2367+
23502368 except json .JSONDecodeError as e :
23512369 return {"error" : f"Failed to parse status response: { str (e )} " }
23522370 except Exception as e :
0 commit comments