ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
# @file purpose: Observability module for browser-use that handles optional lmnr integration with debug mode support
|
||||
"""
|
||||
Observability module for browser-use
|
||||
|
||||
This module provides observability decorators that optionally integrate with lmnr (Laminar) for tracing.
|
||||
If lmnr is not installed, it provides no-op wrappers that accept the same parameters.
|
||||
|
||||
Features:
|
||||
- Optional lmnr integration - works with or without lmnr installed
|
||||
- Debug mode support - observe_debug only traces when in debug mode
|
||||
- Full parameter compatibility with lmnr observe decorator
|
||||
- No-op fallbacks when lmnr is unavailable
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
from functools import wraps
|
||||
from typing import Any, Literal, TypeVar, cast
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Type definitions
|
||||
F = TypeVar('F', bound=Callable[..., Any])
|
||||
|
||||
|
||||
# Check if we're in debug mode
|
||||
def _is_debug_mode() -> bool:
|
||||
"""Check if we're in debug mode based on environment variables or logging level."""
|
||||
|
||||
lmnr_debug_mode = os.getenv('LMNR_LOGGING_LEVEL', '').lower()
|
||||
if lmnr_debug_mode == 'debug':
|
||||
# logger.info('Debug mode is enabled for observability')
|
||||
return True
|
||||
# logger.info('Debug mode is disabled for observability')
|
||||
return False
|
||||
|
||||
|
||||
# Try to import lmnr observe
|
||||
_LMNR_AVAILABLE = False
|
||||
_lmnr_observe = None
|
||||
|
||||
try:
|
||||
from lmnr import observe as _lmnr_observe # type: ignore
|
||||
|
||||
if os.environ.get('BROWSER_USE_VERBOSE_OBSERVABILITY', 'false').lower() == 'true':
|
||||
logger.debug('Lmnr is available for observability')
|
||||
_LMNR_AVAILABLE = True
|
||||
except ImportError:
|
||||
if os.environ.get('BROWSER_USE_VERBOSE_OBSERVABILITY', 'false').lower() == 'true':
|
||||
logger.debug('Lmnr is not available for observability')
|
||||
_LMNR_AVAILABLE = False
|
||||
|
||||
|
||||
def _create_no_op_decorator(
|
||||
name: str | None = None,
|
||||
ignore_input: bool = False,
|
||||
ignore_output: bool = False,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> Callable[[F], F]:
|
||||
"""Create a no-op decorator that accepts all lmnr observe parameters but does nothing."""
|
||||
import asyncio
|
||||
|
||||
def decorator(func: F) -> F:
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
|
||||
@wraps(func)
|
||||
async def async_wrapper(*args, **kwargs):
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
return cast(F, async_wrapper)
|
||||
else:
|
||||
|
||||
@wraps(func)
|
||||
def sync_wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return cast(F, sync_wrapper)
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def observe(
|
||||
name: str | None = None,
|
||||
ignore_input: bool = False,
|
||||
ignore_output: bool = False,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
span_type: Literal['DEFAULT', 'LLM', 'TOOL'] = 'DEFAULT',
|
||||
**kwargs: Any,
|
||||
) -> Callable[[F], F]:
|
||||
"""
|
||||
Observability decorator that traces function execution when lmnr is available.
|
||||
|
||||
This decorator will use lmnr's observe decorator if lmnr is installed,
|
||||
otherwise it will be a no-op that accepts the same parameters.
|
||||
|
||||
Args:
|
||||
name: Name of the span/trace
|
||||
ignore_input: Whether to ignore function input parameters in tracing
|
||||
ignore_output: Whether to ignore function output in tracing
|
||||
metadata: Additional metadata to attach to the span
|
||||
**kwargs: Additional parameters passed to lmnr observe
|
||||
|
||||
Returns:
|
||||
Decorated function that may be traced depending on lmnr availability
|
||||
|
||||
Example:
|
||||
@observe(name="my_function", metadata={"version": "1.0"})
|
||||
def my_function(param1, param2):
|
||||
return param1 + param2
|
||||
"""
|
||||
kwargs = {
|
||||
'name': name,
|
||||
'ignore_input': ignore_input,
|
||||
'ignore_output': ignore_output,
|
||||
'metadata': metadata,
|
||||
'span_type': span_type,
|
||||
**kwargs,
|
||||
}
|
||||
|
||||
if _LMNR_AVAILABLE and _lmnr_observe:
|
||||
# Use the real lmnr observe decorator
|
||||
return cast(Callable[[F], F], _lmnr_observe(**kwargs))
|
||||
else:
|
||||
# Use no-op decorator
|
||||
return _create_no_op_decorator(**kwargs)
|
||||
|
||||
|
||||
def observe_debug(
|
||||
name: str | None = None,
|
||||
ignore_input: bool = False,
|
||||
ignore_output: bool = False,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
span_type: Literal['DEFAULT', 'LLM', 'TOOL'] = 'DEFAULT',
|
||||
**kwargs: Any,
|
||||
) -> Callable[[F], F]:
|
||||
"""
|
||||
Debug-only observability decorator that only traces when in debug mode.
|
||||
|
||||
This decorator will use lmnr's observe decorator if both lmnr is installed
|
||||
AND we're in debug mode, otherwise it will be a no-op.
|
||||
|
||||
Debug mode is determined by:
|
||||
- DEBUG environment variable set to 1/true/yes/on
|
||||
- BROWSER_USE_DEBUG environment variable set to 1/true/yes/on
|
||||
- Root logging level set to DEBUG or lower
|
||||
|
||||
Args:
|
||||
name: Name of the span/trace
|
||||
ignore_input: Whether to ignore function input parameters in tracing
|
||||
ignore_output: Whether to ignore function output in tracing
|
||||
metadata: Additional metadata to attach to the span
|
||||
**kwargs: Additional parameters passed to lmnr observe
|
||||
|
||||
Returns:
|
||||
Decorated function that may be traced only in debug mode
|
||||
|
||||
Example:
|
||||
@observe_debug(ignore_input=True, ignore_output=True,name="debug_function", metadata={"debug": True})
|
||||
def debug_function(param1, param2):
|
||||
return param1 + param2
|
||||
"""
|
||||
kwargs = {
|
||||
'name': name,
|
||||
'ignore_input': ignore_input,
|
||||
'ignore_output': ignore_output,
|
||||
'metadata': metadata,
|
||||
'span_type': span_type,
|
||||
**kwargs,
|
||||
}
|
||||
|
||||
if _LMNR_AVAILABLE and _lmnr_observe and _is_debug_mode():
|
||||
# Use the real lmnr observe decorator only in debug mode
|
||||
return cast(Callable[[F], F], _lmnr_observe(**kwargs))
|
||||
else:
|
||||
# Use no-op decorator (either not in debug mode or lmnr not available)
|
||||
return _create_no_op_decorator(**kwargs)
|
||||
|
||||
|
||||
# Convenience functions for checking availability and debug status
|
||||
def is_lmnr_available() -> bool:
|
||||
"""Check if lmnr is available for tracing."""
|
||||
return _LMNR_AVAILABLE
|
||||
|
||||
|
||||
def is_debug_mode() -> bool:
|
||||
"""Check if we're currently in debug mode."""
|
||||
return _is_debug_mode()
|
||||
|
||||
|
||||
def get_observability_status() -> dict[str, bool]:
|
||||
"""Get the current status of observability features."""
|
||||
return {
|
||||
'lmnr_available': _LMNR_AVAILABLE,
|
||||
'debug_mode': _is_debug_mode(),
|
||||
'observe_active': _LMNR_AVAILABLE,
|
||||
'observe_debug_active': _LMNR_AVAILABLE and _is_debug_mode(),
|
||||
}
|
||||
Reference in New Issue
Block a user