11# SPDX-FileCopyrightText: 2025 GitHub
22# SPDX-License-Identifier: MIT
33
4- import asyncio
5- from threading import Thread
64import argparse
7- import os
8- import sys
9- from dotenv import load_dotenv , find_dotenv
5+ import asyncio
6+ import json
107import logging
11- from logging . handlers import RotatingFileHandler
12- from pprint import pprint , pformat
8+ import os
9+ import pathlib
1310import re
14- import json
11+ import sys
1512import uuid
16- import pathlib
13+ from collections .abc import Callable
14+ from logging .handlers import RotatingFileHandler
15+ from pprint import pformat
1716
18- from .agent import DEFAULT_MODEL , TaskRunHooks , TaskAgentHooks
17+ from agents import Agent , RunContextWrapper , TContext , Tool
18+ from agents .agent import ModelSettings
1919
2020# from agents.run import DEFAULT_MAX_TURNS # XXX: this is 10, we need more than that
21- from agents .exceptions import MaxTurnsExceeded , AgentsException
22- from agents .agent import ModelSettings
23- from agents .mcp import MCPServer , MCPServerStdio , MCPServerSse , MCPServerStreamableHttp , create_static_tool_filter
21+ from agents .exceptions import AgentsException , MaxTurnsExceeded
2422from agents .extensions .handoff_prompt import prompt_with_handoff_instructions
25- from agents import Tool , RunContextWrapper , TContext , Agent
26- from openai import BadRequestError , APITimeoutError , RateLimitError
23+ from agents .mcp import MCPServerSse , MCPServerStdio , MCPServerStreamableHttp , create_static_tool_filter
24+ from dotenv import find_dotenv , load_dotenv
25+ from openai import APITimeoutError , BadRequestError , RateLimitError
2726from openai .types .responses import ResponseTextDeltaEvent
28- from typing import Callable
2927
30- from .shell_utils import shell_tool_call
28+ from .agent import DEFAULT_MODEL , TaskAgent , TaskAgentHooks , TaskRunHooks
29+ from .available_tools import AvailableTools
30+ from .capi import get_AI_token , list_tool_call_models
31+ from .env_utils import TmpEnv
3132from .mcp_utils import (
3233 DEFAULT_MCP_CLIENT_SESSION_TIMEOUT ,
33- ReconnectingMCPServerStdio ,
3434 MCPNamespaceWrap ,
35- mcp_client_params ,
36- mcp_system_prompt ,
35+ ReconnectingMCPServerStdio ,
3736 StreamableMCPThread ,
3837 compress_name ,
38+ mcp_client_params ,
39+ mcp_system_prompt ,
3940)
40- from .render_utils import render_model_output , flush_async_output
41- from .env_utils import TmpEnv
42- from .agent import TaskAgent
43- from .capi import list_tool_call_models , get_AI_token
44- from .available_tools import AvailableTools
4541from .path_utils import log_file_name
42+ from .render_utils import flush_async_output , render_model_output
43+ from .shell_utils import shell_tool_call
4644
4745load_dotenv (find_dotenv (usecwd = True ))
4846
@@ -90,7 +88,7 @@ def parse_prompt_args(available_tools: AvailableTools, user_prompt: str | None =
9088 args = parser .parse_known_args (user_prompt .split (" " ) if user_prompt else None )
9189 except SystemExit as e :
9290 if e .code == 2 :
93- logging .error (f"User provided incomplete prompt: { user_prompt } " )
91+ logging .exception (f"User provided incomplete prompt: { user_prompt } " )
9492 return None , None , None , None , help_msg
9593 p = args [0 ].p .strip () if args [0 ].p else None
9694 t = args [0 ].t .strip () if args [0 ].t else None
@@ -257,14 +255,13 @@ async def mcp_session_task(mcp_servers: list, connected: asyncio.Event, cleanup:
257255 except Exception as e :
258256 print (f"Streamable mcp server process exception: { e } " )
259257 except asyncio .CancelledError :
260- logging .error (f"Timeout on cleanup for mcp server: { server ._name } " )
258+ logging .exception (f"Timeout on cleanup for mcp server: { server ._name } " )
261259 finally :
262260 mcp_servers .remove (s )
263261 except RuntimeError as e :
264- logging .error ( f "RuntimeError in mcp session task: { e } " )
262+ logging .exception ( "RuntimeError in mcp session task" )
265263 except asyncio .CancelledError as e :
266- logging .error (f"Timeout on main session task: { e } " )
267- pass
264+ logging .exception ("Timeout on main session task" )
268265 finally :
269266 mcp_servers .clear ()
270267
@@ -352,17 +349,17 @@ async def _run_streamed():
352349 return
353350 except APITimeoutError :
354351 if not max_retry :
355- logging .error ( f "Max retries for APITimeoutError reached" )
352+ logging .exception ( "Max retries for APITimeoutError reached" )
356353 raise
357354 max_retry -= 1
358355 except RateLimitError :
359356 if rate_limit_backoff == MAX_RATE_LIMIT_BACKOFF :
360- raise APITimeoutError (f "Max rate limit backoff reached" )
357+ raise APITimeoutError ("Max rate limit backoff reached" )
361358 if rate_limit_backoff > MAX_RATE_LIMIT_BACKOFF :
362359 rate_limit_backoff = MAX_RATE_LIMIT_BACKOFF
363360 else :
364361 rate_limit_backoff += rate_limit_backoff
365- logging .error (f"Hit rate limit ... holding for { rate_limit_backoff } " )
362+ logging .exception (f"Hit rate limit ... holding for { rate_limit_backoff } " )
366363 await asyncio .sleep (rate_limit_backoff )
367364
368365 await _run_streamed ()
@@ -371,16 +368,16 @@ async def _run_streamed():
371368 # raise exceptions up to here for anything that indicates a task failure
372369 except MaxTurnsExceeded as e :
373370 await render_model_output (f"** 🤖❗ Max Turns Reached: { e } \n " , async_task = async_task , task_id = task_id )
374- logging .error (f"Exceeded max_turns: { max_turns } " )
371+ logging .exception (f"Exceeded max_turns: { max_turns } " )
375372 except AgentsException as e :
376373 await render_model_output (f"** 🤖❗ Agent Exception: { e } \n " , async_task = async_task , task_id = task_id )
377- logging .error ( f "Agent Exception: { e } " )
374+ logging .exception ( "Agent Exception" )
378375 except BadRequestError as e :
379376 await render_model_output (f"** 🤖❗ Request Error: { e } \n " , async_task = async_task , task_id = task_id )
380- logging .error ( f "Bad Request: { e } " )
377+ logging .exception ( "Bad Request" )
381378 except APITimeoutError as e :
382379 await render_model_output (f"** 🤖❗ Timeout Error: { e } \n " , async_task = async_task , task_id = task_id )
383- logging .error ( f "Bad Request: { e } " )
380+ logging .exception ( "Bad Request" )
384381
385382 if async_task :
386383 await flush_async_output (task_id )
@@ -391,14 +388,14 @@ async def _run_streamed():
391388 # signal mcp sessions task that it can disconnect our servers
392389 start_cleanup .set ()
393390 cleanup_attempts_left = len (mcp_servers )
394- while cleanup_attempts_left and len ( mcp_servers ) :
391+ while cleanup_attempts_left and mcp_servers :
395392 try :
396393 cleanup_attempts_left -= 1
397394 await asyncio .wait_for (mcp_sessions , timeout = MCP_CLEANUP_TIMEOUT )
398- except asyncio .TimeoutError as e :
395+ except asyncio .TimeoutError :
399396 continue
400397 except Exception as e :
401- logging .error ( f "Exception in mcp server cleanup task: { e } " )
398+ logging .exception ( "Exception in mcp server cleanup task" )
402399
403400
404401async def main (available_tools : AvailableTools , p : str | None , t : str | None , cli_globals : dict , prompt : str | None ):
@@ -580,15 +577,15 @@ def preprocess_prompt(prompt: str, tag: str, kv: Callable[[str], dict], kv_subke
580577 async def run_prompts (async_task = False , max_concurrent_tasks = 5 ):
581578 # if this is a shell task, execute that and append the results
582579 if run :
583- await render_model_output (f "** 🤖🐚 Executing Shell Task\n " )
580+ await render_model_output ("** 🤖🐚 Executing Shell Task\n " )
584581 # this allows e.g. shell based jq output to become available for repeat prompts
585582 try :
586583 result = shell_tool_call (run ).content [0 ].model_dump_json ()
587584 last_mcp_tool_results .append (result )
588585 return True
589586 except RuntimeError as e :
590587 await render_model_output (f"** 🤖❗ Shell Task Exception: { e } \n " )
591- logging .error ( f "Shell task error: { e } " )
588+ logging .exception ( "Shell task error" )
592589 return False
593590
594591 tasks = []
0 commit comments