KingNish commited on
Commit
3cf0269
·
1 Parent(s): 10fbb32
Files changed (2) hide show
  1. agent/agent.py +1 -1
  2. agent/tools.py +44 -49
agent/agent.py CHANGED
@@ -33,7 +33,7 @@ class Agent:
33
  base_url: str,
34
  api_key: str,
35
  model: str,
36
- max_iterations: int = 15,
37
  system_prompt: str | None = None,
38
  ) -> None:
39
  self.client = OpenAI(base_url=base_url, api_key=api_key)
 
33
  base_url: str,
34
  api_key: str,
35
  model: str,
36
+ max_iterations: int = 150,
37
  system_prompt: str | None = None,
38
  ) -> None:
39
  self.client = OpenAI(base_url=base_url, api_key=api_key)
agent/tools.py CHANGED
@@ -182,96 +182,91 @@ def _shell_handler(
182
  command: str,
183
  session_id: str = "",
184
  input_text: str = "",
185
- timeout: float = 15.0,
186
- ) -> Generator[str, None, None]:
187
- """Run a shell command with streaming output.
188
 
189
- command (required): The shell command to execute
190
- session_id: Session ID to send input to (omit to auto-generate)
191
  input_text: Text to send to running session's stdin
192
- timeout: Seconds between output updates (default 15)
 
 
 
 
 
193
  """
194
  manager = get_shell_manager()
195
 
196
- # Check if session_id refers to an existing session
197
  existing_session = session_id and session_id in manager.sessions
198
 
199
- # If session exists and has input, send it
200
  if existing_session and input_text:
201
  sent = manager.send_input(session_id, input_text)
202
  if not sent:
203
- yield f"Error: Session '{session_id}' closed or cannot accept input"
204
- return
205
- time.sleep(0.5)
206
  output = manager.poll_output(session_id)
 
 
207
  if output:
208
- yield f"Sent input. New output:\n{output}"
209
- else:
210
- yield "Input sent (no new output yet)"
211
- return
212
 
213
- # If session exists without input, return current output
214
  if existing_session:
215
  output = manager.get_output(session_id)
216
- if output is None:
217
- yield f"Error: Session '{session_id}' not found"
218
- return
219
  running = manager.is_running(session_id)
220
- status = "running" if running else f"exited (code {manager.sessions[session_id].returncode})"
221
- yield f"Session {session_id} [{status}]:\n{output}"
222
- return
 
 
223
 
224
- # Start new command (with provided session_id or auto-generated)
225
  sid = session_id or str(_uuid.uuid4())[:8]
226
  session = manager.start(sid, command)
227
- yield f"Started session {sid} (PID {session.pid})"
228
 
229
- # Stream output poll frequently, yield when there's new output
230
- last_yield = time.time()
231
- while session.is_running():
232
- time.sleep(0.5)
233
- output = session.read_new_output()
 
 
 
 
 
234
  if output:
235
- print(f"Debug: New output for session {sid}:\n{output}")
236
- yield f"[{sid}] Output:\n{output}"
237
- last_yield = time.time()
238
 
239
- # Final output
240
- time.sleep(0.2)
241
- final = session.read_new_output()
242
- code = session.process.returncode
243
- status = f"exited with code {code}" if code is not None else "exited"
244
- if final:
245
- yield f"[{sid}] Final ({status}):\n{final}"
246
- else:
247
- yield f"[{sid}] {status}"
248
 
249
 
250
  SHELL_TOOL = Tool(
251
  name="shell",
252
- description="Run shell commands with streaming output. Supports interactive sessions send input to running commands.",
253
  parameters={
254
  "type": "object",
255
  "properties": {
256
  "command": {
257
  "type": "string",
258
- "description": "The shell command to execute",
259
  },
260
  "session_id": {
261
  "type": "string",
262
- "description": "Session ID to send input to or get output from (omit to start new command)",
263
  },
264
  "input_text": {
265
  "type": "string",
266
  "description": "Text to send to running session's stdin",
267
  },
268
- "timeout": {
269
- "type": "number",
270
- "description": "Seconds between output updates (default 15)",
271
- },
272
  },
273
  "required": ["command"],
274
  },
275
  handler=_shell_handler,
276
- streamable=True,
277
  )
 
182
  command: str,
183
  session_id: str = "",
184
  input_text: str = "",
185
+ ) -> str:
186
+ """Run shell commands interactively.
 
187
 
188
+ command (required): The shell command to execute (omit when checking output or sending input)
189
+ session_id: Session ID to check output or send input to (omit to start new command)
190
  input_text: Text to send to running session's stdin
191
+
192
+ How it works:
193
+ - Start new command: returns session_id immediately (non-blocking)
194
+ - Check output: call with session_id to get current output
195
+ - Send input: call with session_id + input_text
196
+ - Command runs in background, never blocks the agent
197
  """
198
  manager = get_shell_manager()
199
 
 
200
  existing_session = session_id and session_id in manager.sessions
201
 
202
+ # Send input to running session
203
  if existing_session and input_text:
204
  sent = manager.send_input(session_id, input_text)
205
  if not sent:
206
+ return f"Error: Session '{session_id}' closed"
207
+ time.sleep(0.3)
 
208
  output = manager.poll_output(session_id)
209
+ running = manager.is_running(session_id)
210
+ status = "running" if running else f"exited (code {manager.sessions[session_id].returncode})"
211
  if output:
212
+ return f"[{session_id}] {status}:\n{output}"
213
+ return f"[{session_id}] {status} (no new output)"
 
 
214
 
215
+ # Check output of existing session
216
  if existing_session:
217
  output = manager.get_output(session_id)
 
 
 
218
  running = manager.is_running(session_id)
219
+ code = manager.sessions[session_id].returncode
220
+ status = "running" if running else f"exited with code {code}"
221
+ if output:
222
+ return f"[{session_id}] {status}:\n{output}"
223
+ return f"[{session_id}] {status}"
224
 
225
+ # Start new command
226
  sid = session_id or str(_uuid.uuid4())[:8]
227
  session = manager.start(sid, command)
 
228
 
229
+ # Wait a bit to capture initial output (fast commands finish here)
230
+ time.sleep(0.5)
231
+ initial = session.read_new_output()
232
+ running = session.is_running()
233
+
234
+ if not running:
235
+ # Command finished quickly
236
+ code = session.process.returncode
237
+ final = session.read_new_output()
238
+ output = (initial + final).strip()
239
  if output:
240
+ return f"[{sid}] exited with code {code}:\n{output}"
241
+ return f"[{sid}] exited with code {code}"
 
242
 
243
+ # Command still running — return status so model can check later
244
+ if initial:
245
+ return f"[{sid}] running (PID {session.pid}):\n{initial}\n\nCall again with session_id=\"{sid}\" to check output."
246
+ return f"[{sid}] running (PID {session.pid})\n\nCall again with session_id=\"{sid}\" to check output."
 
 
 
 
 
247
 
248
 
249
  SHELL_TOOL = Tool(
250
  name="shell",
251
+ description="Run shell commands interactively. Start command -> returns session_id. Call again with session_id to check output or send input. Never blocks.",
252
  parameters={
253
  "type": "object",
254
  "properties": {
255
  "command": {
256
  "type": "string",
257
+ "description": "The shell command to execute (omit when checking output or sending input)",
258
  },
259
  "session_id": {
260
  "type": "string",
261
+ "description": "Session ID to check output or send input to (omit to start new command)",
262
  },
263
  "input_text": {
264
  "type": "string",
265
  "description": "Text to send to running session's stdin",
266
  },
 
 
 
 
267
  },
268
  "required": ["command"],
269
  },
270
  handler=_shell_handler,
271
+ streamable=False,
272
  )