1111
1212app = FastAPI ()
1313
14- AGENT_DIR = Path (__file__ ).parent .parent # Go up from web_ui/ to agentic/
14+ AGENT_DIR = Path (__file__ ).parent .parent
1515GENERATED_SCRIPTS_DIR = AGENT_DIR / "generated_scripts"
1616
1717
1818class Session :
1919 def __init__ (self ):
2020 self .output_queue = Queue ()
21+ self .process = None
2122
2223 async def _send (self , ws , msg ):
2324 await ws .send_text (json .dumps (msg ))
@@ -35,29 +36,49 @@ async def _send_scripts(self, ws):
3536 "content" : f .read_text ()
3637 })
3738
39+ def send_input (self , text ):
40+ """Send text to the running process's stdin"""
41+ if self .process and self .process .stdin :
42+ try :
43+ self .process .stdin .write (text + "\n " )
44+ self .process .stdin .flush ()
45+ except Exception as e :
46+ self .output_queue .put (("error" , f"Failed to send input: { e } " ))
47+
3848 def _subprocess_thread (self , cmd , cwd ):
3949 try :
40- process = subprocess .Popen (
50+ self . process = subprocess .Popen (
4151 cmd ,
4252 cwd = cwd ,
53+ stdin = subprocess .PIPE ,
4354 stdout = subprocess .PIPE ,
4455 stderr = subprocess .STDOUT ,
4556 text = True ,
4657 bufsize = 1 ,
4758 env = {** os .environ , "PYTHONUNBUFFERED" : "1" }
4859 )
49- for line in process .stdout :
60+ for line in self . process .stdout :
5061 self .output_queue .put (("line" , line .rstrip ()))
51- process .wait ()
52- self .output_queue .put (("exit" , process .returncode ))
62+ self . process .wait ()
63+ self .output_queue .put (("exit" , self . process .returncode ))
5364 except Exception as e :
5465 self .output_queue .put (("error" , str (e )))
66+ finally :
67+ self .process = None
5568
5669 async def run_agent (self , agent_script , scripts_dir , ws , agent_dir = None ):
57- await self ._log (ws , f"started: { agent_script } --scripts { scripts_dir } " )
58-
5970 run_dir = Path (agent_dir ) if agent_dir else AGENT_DIR
60- cmd = [sys .executable , agent_script , "--scripts" , scripts_dir ]
71+ cmd = [sys .executable , agent_script ]
72+
73+ # Add --interactive if the script supports it
74+ if "interactive" in agent_script .lower ():
75+ cmd .append ("--interactive" )
76+
77+ # Add --scripts only if provided
78+ if scripts_dir :
79+ cmd .extend (["--scripts" , scripts_dir ])
80+
81+ await self ._log (ws , f"started: { ' ' .join (cmd )} " )
6182
6283 while not self .output_queue .empty ():
6384 try :
@@ -100,14 +121,26 @@ async def run_agent(self, agent_script, scripts_dir, ws, agent_dir=None):
100121async def ws_endpoint (ws : WebSocket , session_id : str ):
101122 await ws .accept ()
102123 s = sessions .setdefault (session_id , Session ())
124+ agent_task = None
103125 try :
104126 while True :
105127 raw = await ws .receive_text ()
106128 msg = json .loads (raw )
107- agent_script = msg .get ("agent_script" , "libe_agent_basic.py" )
108- scripts_dir = msg .get ("scripts_dir" , "" )
109- agent_dir = msg .get ("agent_dir" , None )
110- if scripts_dir :
111- await s .run_agent (agent_script , scripts_dir , ws , agent_dir = agent_dir )
129+
130+ if msg .get ("type" ) == "input" :
131+ s .send_input (msg .get ("text" , "" ))
132+ else :
133+ # Run agent as background task so we can keep receiving input
134+ if agent_task and not agent_task .done ():
135+ agent_task .cancel ()
136+ agent_task = asyncio .create_task (
137+ s .run_agent (
138+ msg .get ("agent_script" , "" ),
139+ msg .get ("scripts_dir" ) or "" ,
140+ ws ,
141+ agent_dir = msg .get ("agent_dir" )
142+ )
143+ )
112144 except WebSocketDisconnect :
113- pass
145+ if agent_task and not agent_task .done ():
146+ agent_task .cancel ()
0 commit comments