@@ -476,42 +476,42 @@ def _install_packages(self) -> None:
476476 if not pip_pkgs :
477477 return
478478
479+ compute_install_succeeded = False
480+
479481 # If compute provider is available, use it
480482 if self ._compute is not None :
481483 # Use sandbox_type from config
482484 sandbox_type = self ._cfg .get ("sandbox_type" , "subprocess" )
483485 logger .info ("[local_managed] installing packages via compute provider (%s): %s" , sandbox_type , pip_pkgs )
484486 try :
485- import asyncio
486- # Run async operation in sync context
487- loop = asyncio .get_event_loop ()
488- if loop .is_running ():
489- # We're in async context, need to run in executor
487+ try :
488+ asyncio .get_running_loop ()
489+ # We're in async context, run in a separate thread loop.
490490 import threading
491- result = [None ]
492491 exception = [None ]
493-
492+
494493 def run_install ():
495494 try :
496- new_loop = asyncio .new_event_loop ()
497- asyncio .set_event_loop (new_loop )
498- result [0 ] = new_loop .run_until_complete (self ._install_via_compute (pip_pkgs ))
495+ asyncio .run (self ._install_via_compute (pip_pkgs ))
499496 except Exception as e :
500497 exception [0 ] = e
501- finally :
502- new_loop .close ()
503-
498+
504499 thread = threading .Thread (target = run_install )
505500 thread .start ()
506501 thread .join ()
507-
502+
508503 if exception [0 ]:
509504 raise exception [0 ]
510- else :
511- loop .run_until_complete (self ._install_via_compute (pip_pkgs ))
505+ except RuntimeError :
506+ # No running loop in this thread.
507+ asyncio .run (self ._install_via_compute (pip_pkgs ))
508+ compute_install_succeeded = True
512509 except Exception as e :
513510 logger .warning ("[local_managed] compute package install failed: %s" , e )
514511 # Fall through to host installation if allowed
512+
513+ if compute_install_succeeded :
514+ return
515515
516516 # Host installation - only if explicitly allowed
517517 if not self ._cfg .get ("host_packages_ok" , False ):
@@ -544,7 +544,8 @@ async def _install_via_compute(self, pip_pkgs: List[str]) -> None:
544544 await self .provision_compute (config = config )
545545 else :
546546 # Install on existing instance
547- cmd = f"pip install -q { ' ' .join (pip_pkgs )} "
547+ import shlex
548+ cmd = "pip install -q " + " " .join (shlex .quote (pkg ) for pkg in pip_pkgs )
548549 await self .execute_in_compute (cmd , timeout = 120 )
549550
550551 def _ensure_agent (self ) -> Any :
@@ -773,29 +774,32 @@ def interrupt(self) -> None:
773774 # ------------------------------------------------------------------
774775 def retrieve_session (self ) -> Dict [str , Any ]:
775776 """Retrieve current session metadata using unified SessionInfo schema."""
777+ if not self ._session_id :
778+ return {}
779+
776780 self ._sync_usage ()
777781
778782 # Use unified SessionInfo schema for consistency with Anthropic backend
779783 try :
780784 from praisonaiagents .managed import SessionInfo
781785 session_info = SessionInfo (
782- id = self ._session_id or "" ,
783- status = "idle" if self . _session_id else "none" ,
786+ id = self ._session_id ,
787+ status = "idle" ,
784788 usage = {
785789 "input_tokens" : self .total_input_tokens ,
786790 "output_tokens" : self .total_output_tokens ,
787- } if self . _session_id else None
791+ }
788792 )
789793 return session_info .to_dict ()
790794 except ImportError :
791795 # Fallback to old format if SessionInfo not available
792796 return {
793- "id" : self ._session_id or "" ,
794- "status" : "idle" if self . _session_id else "none" ,
797+ "id" : self ._session_id ,
798+ "status" : "idle" ,
795799 "usage" : {
796800 "input_tokens" : self .total_input_tokens ,
797801 "output_tokens" : self .total_output_tokens ,
798- } if self . _session_id else None ,
802+ },
799803 }
800804
801805 def list_sessions (self , ** kwargs ) -> List [Dict [str , Any ]]:
0 commit comments