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
@@ -91,7 +89,7 @@ def parse_prompt_args(available_tools: AvailableTools, user_prompt: str | None =
9189 args = parser .parse_known_args (user_prompt .split (" " ) if user_prompt else None )
9290 except SystemExit as e :
9391 if e .code == 2 :
94- logging .error (f"User provided incomplete prompt: { user_prompt } " )
92+ logging .exception (f"User provided incomplete prompt: { user_prompt } " )
9593 return None , None , None , None , help_msg
9694 p = args [0 ].p .strip () if args [0 ].p else None
9795 t = args [0 ].t .strip () if args [0 ].t else None
@@ -258,14 +256,13 @@ async def mcp_session_task(mcp_servers: list, connected: asyncio.Event, cleanup:
258256 except Exception as e :
259257 print (f"Streamable mcp server process exception: { e } " )
260258 except asyncio .CancelledError :
261- logging .error (f"Timeout on cleanup for mcp server: { server ._name } " )
259+ logging .exception (f"Timeout on cleanup for mcp server: { server ._name } " )
262260 finally :
263261 mcp_servers .remove (s )
264262 except RuntimeError as e :
265- logging .error ( f "RuntimeError in mcp session task: { e } " )
263+ logging .exception ( "RuntimeError in mcp session task" )
266264 except asyncio .CancelledError as e :
267- logging .error (f"Timeout on main session task: { e } " )
268- pass
265+ logging .exception ("Timeout on main session task" )
269266 finally :
270267 mcp_servers .clear ()
271268
@@ -353,17 +350,17 @@ async def _run_streamed():
353350 return
354351 except APITimeoutError :
355352 if not max_retry :
356- logging .error ( f "Max retries for APITimeoutError reached" )
353+ logging .exception ( "Max retries for APITimeoutError reached" )
357354 raise
358355 max_retry -= 1
359356 except RateLimitError :
360357 if rate_limit_backoff == MAX_RATE_LIMIT_BACKOFF :
361- raise APITimeoutError (f "Max rate limit backoff reached" )
358+ raise APITimeoutError ("Max rate limit backoff reached" )
362359 if rate_limit_backoff > MAX_RATE_LIMIT_BACKOFF :
363360 rate_limit_backoff = MAX_RATE_LIMIT_BACKOFF
364361 else :
365362 rate_limit_backoff += rate_limit_backoff
366- logging .error (f"Hit rate limit ... holding for { rate_limit_backoff } " )
363+ logging .exception (f"Hit rate limit ... holding for { rate_limit_backoff } " )
367364 await asyncio .sleep (rate_limit_backoff )
368365
369366 await _run_streamed ()
@@ -372,16 +369,16 @@ async def _run_streamed():
372369 # raise exceptions up to here for anything that indicates a task failure
373370 except MaxTurnsExceeded as e :
374371 await render_model_output (f"** 🤖❗ Max Turns Reached: { e } \n " , async_task = async_task , task_id = task_id )
375- logging .error (f"Exceeded max_turns: { max_turns } " )
372+ logging .exception (f"Exceeded max_turns: { max_turns } " )
376373 except AgentsException as e :
377374 await render_model_output (f"** 🤖❗ Agent Exception: { e } \n " , async_task = async_task , task_id = task_id )
378- logging .error ( f "Agent Exception: { e } " )
375+ logging .exception ( "Agent Exception" )
379376 except BadRequestError as e :
380377 await render_model_output (f"** 🤖❗ Request Error: { e } \n " , async_task = async_task , task_id = task_id )
381- logging .error ( f "Bad Request: { e } " )
378+ logging .exception ( "Bad Request" )
382379 except APITimeoutError as e :
383380 await render_model_output (f"** 🤖❗ Timeout Error: { e } \n " , async_task = async_task , task_id = task_id )
384- logging .error ( f "Bad Request: { e } " )
381+ logging .exception ( "Bad Request" )
385382
386383 if async_task :
387384 await flush_async_output (task_id )
@@ -392,14 +389,14 @@ async def _run_streamed():
392389 # signal mcp sessions task that it can disconnect our servers
393390 start_cleanup .set ()
394391 cleanup_attempts_left = len (mcp_servers )
395- while cleanup_attempts_left and len ( mcp_servers ) :
392+ while cleanup_attempts_left and mcp_servers :
396393 try :
397394 cleanup_attempts_left -= 1
398395 await asyncio .wait_for (mcp_sessions , timeout = MCP_CLEANUP_TIMEOUT )
399- except asyncio .TimeoutError as e :
396+ except asyncio .TimeoutError :
400397 continue
401398 except Exception as e :
402- logging .error ( f "Exception in mcp server cleanup task: { e } " )
399+ logging .exception ( "Exception in mcp server cleanup task" )
403400
404401
405402async def main (available_tools : AvailableTools , p : str | None , t : str | None , cli_globals : dict , prompt : str | None ):
@@ -581,15 +578,15 @@ def preprocess_prompt(prompt: str, tag: str, kv: Callable[[str], dict], kv_subke
581578 async def run_prompts (async_task = False , max_concurrent_tasks = 5 ):
582579 # if this is a shell task, execute that and append the results
583580 if run :
584- await render_model_output (f "** 🤖🐚 Executing Shell Task\n " )
581+ await render_model_output ("** 🤖🐚 Executing Shell Task\n " )
585582 # this allows e.g. shell based jq output to become available for repeat prompts
586583 try :
587584 result = shell_tool_call (run ).content [0 ].model_dump_json ()
588585 last_mcp_tool_results .append (result )
589586 return True
590587 except RuntimeError as e :
591588 await render_model_output (f"** 🤖❗ Shell Task Exception: { e } \n " )
592- logging .error ( f "Shell task error: { e } " )
589+ logging .exception ( "Shell task error" )
593590 return False
594591
595592 tasks = []
0 commit comments