tinyagent-py 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,213 @@
1
+ import logging
2
+ from typing import Dict, Optional, Union, List
3
+
4
+ class LoggingManager:
5
+ """
6
+ A hook for TinyAgent that provides granular logging control for different modules.
7
+
8
+ This allows setting different log levels for each module in the TinyAgent ecosystem
9
+ without affecting external libraries like httpx.
10
+ """
11
+
12
+ def __init__(self, default_level: int = logging.INFO, silence_others: bool = True):
13
+ """
14
+ Initialize the LoggingManager.
15
+
16
+ Args:
17
+ default_level: Default logging level for all modules
18
+ silence_others: If True, silence all non-tinyagent loggers by default
19
+ """
20
+ self.default_level = default_level
21
+ self.module_loggers: Dict[str, logging.Logger] = {}
22
+ self.module_levels: Dict[str, int] = {}
23
+
24
+ # Grab the root logger
25
+ self.root_logger = logging.getLogger()
26
+ self.external_logger_levels: Dict[str, int] = {}
27
+
28
+ if silence_others:
29
+ # 1) store its original level
30
+ self.root_logger_original_level = self.root_logger.level
31
+ # 2) strip away _any_ existing handlers (e.g. from basicConfig in libs)
32
+ for h in list(self.root_logger.handlers):
33
+ self.root_logger.removeHandler(h)
34
+ # 3) raise level so that only WARNING+ pass through by default
35
+ self.root_logger.setLevel(logging.WARNING)
36
+
37
+ def get_logger(self, module_name: str) -> logging.Logger:
38
+ """
39
+ Get or create a logger for a specific module.
40
+
41
+ Args:
42
+ module_name: Name of the module (e.g., 'tinyagent.tiny_agent')
43
+
44
+ Returns:
45
+ A configured logger for the module
46
+ """
47
+ if module_name in self.module_loggers:
48
+ return self.module_loggers[module_name]
49
+
50
+ # Create a new logger
51
+ logger = logging.getLogger(module_name)
52
+
53
+ # Set level from configured module levels or default
54
+ level = self.module_levels.get(module_name, self.default_level)
55
+ logger.setLevel(level)
56
+
57
+ # Ensure propagation is enabled for tinyagent loggers
58
+ if module_name.startswith('tinyagent'):
59
+ logger.propagate = True
60
+
61
+ # Store the logger
62
+ self.module_loggers[module_name] = logger
63
+
64
+ return logger
65
+
66
+ def set_level(self, module_name: str, level: Union[int, str]) -> None:
67
+ """
68
+ Set the logging level for a specific module.
69
+
70
+ Args:
71
+ module_name: Name of the module (e.g., 'tinyagent.tiny_agent')
72
+ level: Logging level (can be int or string like 'DEBUG')
73
+ """
74
+ # Convert string level to int if needed
75
+ if isinstance(level, str):
76
+ level = getattr(logging, level.upper())
77
+
78
+ # Store the level setting
79
+ self.module_levels[module_name] = level
80
+
81
+ # Update existing logger if it exists
82
+ if module_name in self.module_loggers:
83
+ self.module_loggers[module_name].setLevel(level)
84
+
85
+ def set_levels(self, config: Dict[str, Union[int, str]]) -> None:
86
+ """
87
+ Set multiple logging levels at once.
88
+
89
+ Args:
90
+ config: Dictionary mapping module names to levels
91
+ """
92
+ for module_name, level in config.items():
93
+ self.set_level(module_name, level)
94
+
95
+ def silence_external_loggers(self, logger_names: List[str], level: int = logging.WARNING) -> None:
96
+ """
97
+ Silence external loggers (like httpx) by setting them to a higher level.
98
+
99
+ Args:
100
+ logger_names: List of external logger names to silence
101
+ level: Level to set for these loggers (default: WARNING)
102
+ """
103
+ for name in logger_names:
104
+ logger = logging.getLogger(name)
105
+ # Store original level
106
+ self.external_logger_levels[name] = logger.level
107
+ # Set new level
108
+ logger.setLevel(level)
109
+
110
+ def restore_external_loggers(self) -> None:
111
+ """Restore external loggers to their original levels."""
112
+ for name, level in self.external_logger_levels.items():
113
+ logging.getLogger(name).setLevel(level)
114
+
115
+ # Restore root logger level if we changed it
116
+ if hasattr(self, 'root_logger_original_level'):
117
+ self.root_logger.setLevel(self.root_logger_original_level)
118
+
119
+ def configure_handler(self, handler: logging.Handler,
120
+ format_string: Optional[str] = None,
121
+ level: Optional[int] = None) -> None:
122
+ """
123
+ Configure a logging handler with format and level.
124
+
125
+ Args:
126
+ handler: The handler to configure
127
+ format_string: Optional format string for the handler
128
+ level: Optional level for the handler
129
+ """
130
+ if format_string:
131
+ formatter = logging.Formatter(format_string)
132
+ handler.setFormatter(formatter)
133
+
134
+ if level is not None:
135
+ handler.setLevel(level)
136
+
137
+ # Add to root logger if not already present
138
+ if handler not in self.root_logger.handlers:
139
+ self.root_logger.addHandler(handler)
140
+
141
+
142
+ async def run_example():
143
+ """Example usage of LoggingManager with TinyAgent."""
144
+ import os
145
+ import sys
146
+ from tinyagent import TinyAgent
147
+ from tinyagent.hooks.rich_ui_callback import RichUICallback
148
+
149
+ # Create the logging manager with silence_others=True
150
+ log_manager = LoggingManager(default_level=logging.INFO, silence_others=True)
151
+
152
+ # Configure different levels for different modules
153
+ log_manager.set_levels({
154
+ 'tinyagent.tiny_agent': logging.INFO,
155
+ 'tinyagent.mcp_client': logging.INFO,
156
+ 'tinyagent.hooks.rich_ui_callback': logging.DEBUG, # Debug for RichUICallback
157
+ 'tinyagent.hooks.logging_manager': logging.DEBUG, # Debug for this module
158
+ })
159
+
160
+ # Explicitly silence specific external loggers if needed
161
+ log_manager.silence_external_loggers(['httpx', 'asyncio', 'litellm', 'openai'], logging.WARNING)
162
+
163
+ # Add a console handler with custom format
164
+ console_handler = logging.StreamHandler(sys.stdout)
165
+ log_manager.configure_handler(
166
+ console_handler,
167
+ format_string='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
168
+ level=logging.DEBUG
169
+ )
170
+
171
+ # Get module-specific loggers
172
+ agent_logger = log_manager.get_logger('tinyagent.tiny_agent')
173
+ ui_logger = log_manager.get_logger('tinyagent.hooks.rich_ui_callback')
174
+ mcp_logger = log_manager.get_logger('tinyagent.mcp_client')
175
+ log_manager_logger = log_manager.get_logger('tinyagent.hooks.logging_manager')
176
+
177
+ log_manager_logger.debug("Starting LoggingManager example")
178
+ agent_logger.info("Initializing TinyAgent")
179
+
180
+ # Get API key from environment
181
+ api_key = os.environ.get("OPENAI_API_KEY")
182
+ if not api_key:
183
+ agent_logger.error("Please set the OPENAI_API_KEY environment variable")
184
+ return
185
+
186
+ # Initialize the agent with our logger
187
+ agent = TinyAgent(model="gpt-4.1-mini", api_key=api_key, logger=agent_logger)
188
+
189
+ # Add the Rich UI callback with our logger
190
+ rich_ui = RichUICallback(
191
+ markdown=True,
192
+ show_message=True,
193
+ show_thinking=True,
194
+ show_tool_calls=True,
195
+ logger=ui_logger # Pass DEBUG level logger to RichUICallback
196
+ )
197
+ agent.add_callback(rich_ui)
198
+
199
+ # Run the agent with a user query
200
+ user_input = "What is the capital of France?"
201
+ agent_logger.info(f"Running agent with input: {user_input}")
202
+ result = await agent.run(user_input)
203
+
204
+ agent_logger.info(f"Final result: {result}")
205
+
206
+ # Clean up
207
+ await agent.close()
208
+ log_manager_logger.debug("Example completed")
209
+
210
+
211
+ if __name__ == "__main__":
212
+ import asyncio
213
+ asyncio.run(run_example())