Skip to content

Commit f91f01b

Browse files
committed
fix: improve logger, error handling, and documentation
- Fix duplicate logger handler issue by checking existing handlers - Improve error message matching in retry logic (case-insensitive) - Add comprehensive docstrings to utility functions - Add default parameter value to extract_text_from_message - Enhance type hints and documentation for better IDE support These changes improve code robustness, maintainability, and developer experience.
1 parent 31a4d36 commit f91f01b

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

qwen_agent/llm/base.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,18 @@ def retry_model_service(
808808
fn,
809809
max_retries: int = 10,
810810
) -> Any:
811-
"""Retry a function"""
811+
"""Retry a function call with exponential backoff on ModelServiceError.
812+
813+
Args:
814+
fn: The function to retry.
815+
max_retries: Maximum number of retry attempts (default: 10).
816+
817+
Returns:
818+
The result of the function call.
819+
820+
Raises:
821+
ModelServiceError: If all retry attempts fail.
822+
"""
812823

813824
num_retries, delay = 0, 1.0
814825
while True:
@@ -823,7 +834,18 @@ def retry_model_service_iterator(
823834
it_fn,
824835
max_retries: int = 10,
825836
) -> Iterator:
826-
"""Retry an iterator"""
837+
"""Retry an iterator with exponential backoff on ModelServiceError.
838+
839+
Args:
840+
it_fn: The iterator function to retry.
841+
max_retries: Maximum number of retry attempts (default: 10).
842+
843+
Yields:
844+
The items from the iterator.
845+
846+
Raises:
847+
ModelServiceError: If all retry attempts fail.
848+
"""
827849

828850
num_retries, delay = 0, 1.0
829851
while True:
@@ -856,11 +878,13 @@ def _raise_or_delay(
856878
# If harmful input or output detected, let it fail
857879
if e.code == 'DataInspectionFailed':
858880
raise e
859-
if 'inappropriate content' in str(e):
881+
882+
error_message = str(e).lower()
883+
if 'inappropriate content' in error_message:
860884
raise e
861885

862886
# Retry is meaningless if the input is too long
863-
if 'maximum context length' in str(e):
887+
if 'maximum context length' in error_message or 'context length' in error_message and 'exceed' in error_message:
864888
raise e
865889

866890
logger.warning('ModelServiceError - ' + str(e).strip('\n'))

qwen_agent/log.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,18 @@ def setup_logger(level=None):
2323
else:
2424
level = logging.INFO
2525

26+
_logger = logging.getLogger('qwen_agent_logger')
27+
28+
# Avoid adding duplicate handlers if logger is already configured
29+
if _logger.handlers:
30+
_logger.setLevel(level)
31+
return _logger
32+
2633
handler = logging.StreamHandler()
2734
# Do not run handler.setLevel(level) so that users can change the level via logger.setLevel later
2835
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(lineno)d - %(levelname)s - %(message)s')
2936
handler.setFormatter(formatter)
3037

31-
_logger = logging.getLogger('qwen_agent_logger')
3238
_logger.setLevel(level)
3339
_logger.addHandler(handler)
3440
return _logger

qwen_agent/utils/utils.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,20 @@ def extract_code(text: str) -> str:
298298

299299

300300
def json_loads(text: str) -> dict:
301+
"""Parse JSON text with fallback to json5 for more lenient parsing.
302+
303+
This function handles code blocks wrapped in triple backticks and attempts
304+
standard JSON parsing first, then falls back to json5 for more flexible parsing.
305+
306+
Args:
307+
text: The JSON text to parse.
308+
309+
Returns:
310+
The parsed JSON as a dictionary.
311+
312+
Raises:
313+
json.decoder.JSONDecodeError: If both json and json5 parsing fail.
314+
"""
301315
text = text.strip('\n')
302316
if text.startswith('```') and text.endswith('\n```'):
303317
text = '\n'.join(text.split('\n')[1:-1])
@@ -450,9 +464,22 @@ def save_audio_to_file(base_64: str, file_name: str):
450464

451465
def extract_text_from_message(
452466
msg: Message,
453-
add_upload_info: bool,
467+
add_upload_info: bool = False,
454468
lang: Literal['auto', 'en', 'zh'] = 'auto',
455469
) -> str:
470+
"""Extract text content from a message, handling both string and list content types.
471+
472+
Args:
473+
msg: The message to extract text from.
474+
add_upload_info: Whether to include upload information in the extracted text.
475+
lang: Language for formatting ('auto', 'en', or 'zh').
476+
477+
Returns:
478+
The extracted and stripped text content.
479+
480+
Raises:
481+
TypeError: If msg.content is neither a string nor a list.
482+
"""
456483
if isinstance(msg.content, list):
457484
text = format_as_text_message(msg, add_upload_info=add_upload_info, lang=lang).content
458485
elif isinstance(msg.content, str):

0 commit comments

Comments
 (0)