webagents 0.1.12__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.
- webagents/__init__.py +18 -0
- webagents/agents/__init__.py +13 -0
- webagents/agents/core/__init__.py +19 -0
- webagents/agents/core/base_agent.py +1834 -0
- webagents/agents/core/handoffs.py +293 -0
- webagents/agents/handoffs/__init__.py +0 -0
- webagents/agents/interfaces/__init__.py +0 -0
- webagents/agents/lifecycle/__init__.py +0 -0
- webagents/agents/skills/__init__.py +109 -0
- webagents/agents/skills/base.py +136 -0
- webagents/agents/skills/core/__init__.py +8 -0
- webagents/agents/skills/core/guardrails/__init__.py +0 -0
- webagents/agents/skills/core/llm/__init__.py +0 -0
- webagents/agents/skills/core/llm/anthropic/__init__.py +1 -0
- webagents/agents/skills/core/llm/litellm/__init__.py +10 -0
- webagents/agents/skills/core/llm/litellm/skill.py +538 -0
- webagents/agents/skills/core/llm/openai/__init__.py +1 -0
- webagents/agents/skills/core/llm/xai/__init__.py +1 -0
- webagents/agents/skills/core/mcp/README.md +375 -0
- webagents/agents/skills/core/mcp/__init__.py +15 -0
- webagents/agents/skills/core/mcp/skill.py +731 -0
- webagents/agents/skills/core/memory/__init__.py +11 -0
- webagents/agents/skills/core/memory/long_term_memory/__init__.py +10 -0
- webagents/agents/skills/core/memory/long_term_memory/memory_skill.py +639 -0
- webagents/agents/skills/core/memory/short_term_memory/__init__.py +9 -0
- webagents/agents/skills/core/memory/short_term_memory/skill.py +341 -0
- webagents/agents/skills/core/memory/vector_memory/skill.py +447 -0
- webagents/agents/skills/core/planning/__init__.py +9 -0
- webagents/agents/skills/core/planning/planner.py +343 -0
- webagents/agents/skills/ecosystem/__init__.py +0 -0
- webagents/agents/skills/ecosystem/crewai/__init__.py +1 -0
- webagents/agents/skills/ecosystem/database/__init__.py +1 -0
- webagents/agents/skills/ecosystem/filesystem/__init__.py +0 -0
- webagents/agents/skills/ecosystem/google/__init__.py +0 -0
- webagents/agents/skills/ecosystem/google/calendar/__init__.py +6 -0
- webagents/agents/skills/ecosystem/google/calendar/skill.py +306 -0
- webagents/agents/skills/ecosystem/n8n/__init__.py +0 -0
- webagents/agents/skills/ecosystem/openai_agents/__init__.py +0 -0
- webagents/agents/skills/ecosystem/web/__init__.py +0 -0
- webagents/agents/skills/ecosystem/zapier/__init__.py +0 -0
- webagents/agents/skills/robutler/__init__.py +11 -0
- webagents/agents/skills/robutler/auth/README.md +63 -0
- webagents/agents/skills/robutler/auth/__init__.py +17 -0
- webagents/agents/skills/robutler/auth/skill.py +354 -0
- webagents/agents/skills/robutler/crm/__init__.py +18 -0
- webagents/agents/skills/robutler/crm/skill.py +368 -0
- webagents/agents/skills/robutler/discovery/README.md +281 -0
- webagents/agents/skills/robutler/discovery/__init__.py +16 -0
- webagents/agents/skills/robutler/discovery/skill.py +230 -0
- webagents/agents/skills/robutler/kv/__init__.py +6 -0
- webagents/agents/skills/robutler/kv/skill.py +80 -0
- webagents/agents/skills/robutler/message_history/__init__.py +9 -0
- webagents/agents/skills/robutler/message_history/skill.py +270 -0
- webagents/agents/skills/robutler/messages/__init__.py +0 -0
- webagents/agents/skills/robutler/nli/__init__.py +13 -0
- webagents/agents/skills/robutler/nli/skill.py +687 -0
- webagents/agents/skills/robutler/notifications/__init__.py +5 -0
- webagents/agents/skills/robutler/notifications/skill.py +141 -0
- webagents/agents/skills/robutler/payments/__init__.py +41 -0
- webagents/agents/skills/robutler/payments/exceptions.py +255 -0
- webagents/agents/skills/robutler/payments/skill.py +610 -0
- webagents/agents/skills/robutler/storage/__init__.py +10 -0
- webagents/agents/skills/robutler/storage/files/__init__.py +9 -0
- webagents/agents/skills/robutler/storage/files/skill.py +445 -0
- webagents/agents/skills/robutler/storage/json/__init__.py +9 -0
- webagents/agents/skills/robutler/storage/json/skill.py +336 -0
- webagents/agents/skills/robutler/storage/kv/skill.py +88 -0
- webagents/agents/skills/robutler/storage.py +389 -0
- webagents/agents/tools/__init__.py +0 -0
- webagents/agents/tools/decorators.py +426 -0
- webagents/agents/tracing/__init__.py +0 -0
- webagents/agents/workflows/__init__.py +0 -0
- webagents/api/__init__.py +17 -0
- webagents/api/client.py +1207 -0
- webagents/api/types.py +253 -0
- webagents/scripts/__init__.py +0 -0
- webagents/server/__init__.py +28 -0
- webagents/server/context/__init__.py +0 -0
- webagents/server/context/context_vars.py +121 -0
- webagents/server/core/__init__.py +0 -0
- webagents/server/core/app.py +843 -0
- webagents/server/core/middleware.py +69 -0
- webagents/server/core/models.py +98 -0
- webagents/server/core/monitoring.py +59 -0
- webagents/server/endpoints/__init__.py +0 -0
- webagents/server/interfaces/__init__.py +0 -0
- webagents/server/middleware.py +330 -0
- webagents/server/models.py +92 -0
- webagents/server/monitoring.py +659 -0
- webagents/utils/__init__.py +0 -0
- webagents/utils/logging.py +359 -0
- webagents-0.1.12.dist-info/METADATA +99 -0
- webagents-0.1.12.dist-info/RECORD +96 -0
- webagents-0.1.12.dist-info/WHEEL +4 -0
- webagents-0.1.12.dist-info/entry_points.txt +2 -0
- webagents-0.1.12.dist-info/licenses/LICENSE +1 -0
@@ -0,0 +1,359 @@
|
|
1
|
+
"""
|
2
|
+
Robutler V2.0 Logging System
|
3
|
+
|
4
|
+
Comprehensive logging with color-coded agent names, structured output,
|
5
|
+
and context-aware logging for agents, skills, and server components.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import logging
|
9
|
+
import sys
|
10
|
+
import time
|
11
|
+
from typing import Optional, Dict, Any
|
12
|
+
from colorama import Fore, Back, Style, init
|
13
|
+
from datetime import datetime
|
14
|
+
from contextvars import ContextVar
|
15
|
+
|
16
|
+
# Initialize colorama for cross-platform color support
|
17
|
+
init(autoreset=True)
|
18
|
+
|
19
|
+
# Context variables for logging
|
20
|
+
CURRENT_AGENT: ContextVar[Optional[str]] = ContextVar('current_agent', default=None)
|
21
|
+
CURRENT_REQUEST_ID: ContextVar[Optional[str]] = ContextVar('current_request_id', default=None)
|
22
|
+
CURRENT_USER_ID: ContextVar[Optional[str]] = ContextVar('current_user_id', default=None)
|
23
|
+
|
24
|
+
# Color mapping for different agent types/names
|
25
|
+
AGENT_COLORS = {
|
26
|
+
# Core system colors
|
27
|
+
'system': Fore.CYAN,
|
28
|
+
'server': Fore.BLUE,
|
29
|
+
'router': Fore.MAGENTA,
|
30
|
+
|
31
|
+
# Agent name-based colors (hash-based for consistency)
|
32
|
+
'default': Fore.GREEN,
|
33
|
+
}
|
34
|
+
|
35
|
+
def get_agent_color(agent_name: str) -> str:
|
36
|
+
"""Get consistent color for agent name based on hash"""
|
37
|
+
if agent_name in AGENT_COLORS:
|
38
|
+
return AGENT_COLORS[agent_name]
|
39
|
+
|
40
|
+
# Generate consistent color based on agent name hash
|
41
|
+
colors = [Fore.GREEN, Fore.YELLOW, Fore.BLUE, Fore.MAGENTA, Fore.CYAN, Fore.RED]
|
42
|
+
color_index = hash(agent_name) % len(colors)
|
43
|
+
return colors[color_index]
|
44
|
+
|
45
|
+
class RobutlerFormatter(logging.Formatter):
|
46
|
+
"""Custom formatter with color-coded agent names and structured output"""
|
47
|
+
|
48
|
+
def format(self, record):
|
49
|
+
# Get context information
|
50
|
+
agent_name = CURRENT_AGENT.get() or getattr(record, 'agent_name', None)
|
51
|
+
request_id = CURRENT_REQUEST_ID.get() or getattr(record, 'request_id', None)
|
52
|
+
user_id = CURRENT_USER_ID.get() or getattr(record, 'user_id', None)
|
53
|
+
|
54
|
+
# Format timestamp
|
55
|
+
timestamp = datetime.fromtimestamp(record.created).strftime('%H:%M:%S.%f')[:-3]
|
56
|
+
|
57
|
+
# Format level with color
|
58
|
+
level_colors = {
|
59
|
+
'DEBUG': Fore.WHITE,
|
60
|
+
'INFO': Fore.GREEN,
|
61
|
+
'WARNING': Fore.YELLOW,
|
62
|
+
'ERROR': Fore.RED,
|
63
|
+
'CRITICAL': Fore.RED + Back.WHITE
|
64
|
+
}
|
65
|
+
level_color = level_colors.get(record.levelname, Fore.WHITE)
|
66
|
+
colored_level = f"{level_color}{record.levelname:8s}{Style.RESET_ALL}"
|
67
|
+
|
68
|
+
# Format agent name with color
|
69
|
+
if agent_name:
|
70
|
+
agent_color = get_agent_color(agent_name)
|
71
|
+
colored_agent = f"{agent_color}{agent_name:15s}{Style.RESET_ALL}"
|
72
|
+
else:
|
73
|
+
# Try to extract agent name from logger name (e.g., openlicense-image.tool)
|
74
|
+
logger_parts = record.name.split('.')
|
75
|
+
if len(logger_parts) > 0 and '-' in logger_parts[0]:
|
76
|
+
potential_agent = logger_parts[0]
|
77
|
+
agent_color = get_agent_color(potential_agent)
|
78
|
+
colored_agent = f"{agent_color}{potential_agent[:15]:15s}{Style.RESET_ALL}"
|
79
|
+
else:
|
80
|
+
colored_agent = f"{'system':15s}"
|
81
|
+
|
82
|
+
# Format component (logger name)
|
83
|
+
component = record.name.split('.')[-1] if '.' in record.name else record.name
|
84
|
+
# Truncate very long component names
|
85
|
+
if len(component) > 12:
|
86
|
+
component = component[:12]
|
87
|
+
|
88
|
+
# Build context string
|
89
|
+
context_parts = []
|
90
|
+
if request_id:
|
91
|
+
context_parts.append(f"req={request_id[:8]}")
|
92
|
+
if user_id:
|
93
|
+
context_parts.append(f"user={user_id[:8]}")
|
94
|
+
|
95
|
+
context_str = f" [{':'.join(context_parts)}]" if context_parts else ""
|
96
|
+
|
97
|
+
# Format the log message
|
98
|
+
message = record.getMessage()
|
99
|
+
|
100
|
+
# Build final log line
|
101
|
+
log_line = f"{Fore.WHITE}{timestamp}{Style.RESET_ALL} {colored_level} {colored_agent} {Fore.BLUE}{component:12s}{Style.RESET_ALL}{context_str} {message}"
|
102
|
+
|
103
|
+
# Add exception info if present
|
104
|
+
if record.exc_info:
|
105
|
+
log_line += '\n' + self.formatException(record.exc_info)
|
106
|
+
|
107
|
+
return log_line
|
108
|
+
|
109
|
+
class AgentContextAdapter(logging.LoggerAdapter):
|
110
|
+
"""Logger adapter that automatically includes agent context"""
|
111
|
+
|
112
|
+
def __init__(self, logger, agent_name: str):
|
113
|
+
super().__init__(logger, {})
|
114
|
+
self.agent_name = agent_name
|
115
|
+
|
116
|
+
def process(self, msg, kwargs):
|
117
|
+
# Add agent context to log record
|
118
|
+
extra = kwargs.get('extra', {})
|
119
|
+
extra['agent_name'] = self.agent_name
|
120
|
+
|
121
|
+
# Add current context if available
|
122
|
+
request_id = CURRENT_REQUEST_ID.get()
|
123
|
+
user_id = CURRENT_USER_ID.get()
|
124
|
+
|
125
|
+
if request_id:
|
126
|
+
extra['request_id'] = request_id
|
127
|
+
if user_id:
|
128
|
+
extra['user_id'] = user_id
|
129
|
+
|
130
|
+
kwargs['extra'] = extra
|
131
|
+
return msg, kwargs
|
132
|
+
|
133
|
+
def setup_logging(level: str = "INFO", log_file: Optional[str] = None) -> None:
|
134
|
+
"""Setup the Robutler logging system"""
|
135
|
+
|
136
|
+
# Convert string level to logging constant
|
137
|
+
numeric_level = getattr(logging, level.upper(), logging.INFO)
|
138
|
+
|
139
|
+
# Create root logger
|
140
|
+
root_logger = logging.getLogger('robutler')
|
141
|
+
root_logger.setLevel(numeric_level)
|
142
|
+
|
143
|
+
# Clear any existing handlers
|
144
|
+
root_logger.handlers.clear()
|
145
|
+
|
146
|
+
# Console handler with color formatter
|
147
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
148
|
+
console_handler.setLevel(numeric_level)
|
149
|
+
console_handler.setFormatter(RobutlerFormatter())
|
150
|
+
root_logger.addHandler(console_handler)
|
151
|
+
|
152
|
+
# File handler if specified (without colors)
|
153
|
+
if log_file:
|
154
|
+
file_handler = logging.FileHandler(log_file)
|
155
|
+
file_handler.setLevel(numeric_level)
|
156
|
+
file_formatter = logging.Formatter(
|
157
|
+
'%(asctime)s %(levelname)-8s %(name)-20s [%(agent_name)s] %(message)s',
|
158
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
159
|
+
)
|
160
|
+
file_handler.setFormatter(file_formatter)
|
161
|
+
root_logger.addHandler(file_handler)
|
162
|
+
|
163
|
+
# Disable propagation to avoid duplicate logs
|
164
|
+
root_logger.propagate = False
|
165
|
+
|
166
|
+
# Set levels for noisy libraries
|
167
|
+
logging.getLogger('urllib3').setLevel(logging.WARNING)
|
168
|
+
logging.getLogger('httpx').setLevel(logging.WARNING)
|
169
|
+
logging.getLogger('openai').setLevel(logging.WARNING)
|
170
|
+
|
171
|
+
# Configure LiteLLM logging to use our formatter
|
172
|
+
litellm_logger = logging.getLogger('LiteLLM')
|
173
|
+
litellm_logger.setLevel(logging.WARNING) # Only show warnings and errors
|
174
|
+
# Clear any existing handlers from LiteLLM
|
175
|
+
litellm_logger.handlers.clear()
|
176
|
+
# Add our console handler with formatter
|
177
|
+
litellm_handler = logging.StreamHandler(sys.stdout)
|
178
|
+
litellm_handler.setFormatter(RobutlerFormatter())
|
179
|
+
litellm_logger.addHandler(litellm_handler)
|
180
|
+
litellm_logger.propagate = False
|
181
|
+
|
182
|
+
# Also configure the root logger to catch any unconfigured loggers
|
183
|
+
# This will catch any dynamically created loggers that don't have handlers
|
184
|
+
root = logging.getLogger()
|
185
|
+
if not root.handlers:
|
186
|
+
# Only add handler if root doesn't have one already
|
187
|
+
root_handler = logging.StreamHandler(sys.stdout)
|
188
|
+
root_handler.setFormatter(RobutlerFormatter())
|
189
|
+
root_handler.setLevel(numeric_level)
|
190
|
+
root.addHandler(root_handler)
|
191
|
+
else:
|
192
|
+
# Update existing root handlers to use our formatter
|
193
|
+
for handler in root.handlers:
|
194
|
+
if isinstance(handler, logging.StreamHandler):
|
195
|
+
handler.setFormatter(RobutlerFormatter())
|
196
|
+
handler.setLevel(numeric_level)
|
197
|
+
|
198
|
+
def get_logger(name: str, agent_name: Optional[str] = None) -> logging.Logger:
|
199
|
+
"""Get a logger for a specific component, optionally with agent context"""
|
200
|
+
|
201
|
+
logger_name = f"robutler.{name}" if not name.startswith('robutler') else name
|
202
|
+
logger = logging.getLogger(logger_name)
|
203
|
+
|
204
|
+
if agent_name:
|
205
|
+
return AgentContextAdapter(logger, agent_name)
|
206
|
+
|
207
|
+
return logger
|
208
|
+
|
209
|
+
def set_agent_context(agent_name: str, request_id: Optional[str] = None, user_id: Optional[str] = None):
|
210
|
+
"""Set the current agent context for logging"""
|
211
|
+
CURRENT_AGENT.set(agent_name)
|
212
|
+
if request_id:
|
213
|
+
CURRENT_REQUEST_ID.set(request_id)
|
214
|
+
if user_id:
|
215
|
+
CURRENT_USER_ID.set(user_id)
|
216
|
+
|
217
|
+
def clear_agent_context():
|
218
|
+
"""Clear the current agent context"""
|
219
|
+
CURRENT_AGENT.set(None)
|
220
|
+
CURRENT_REQUEST_ID.set(None)
|
221
|
+
CURRENT_USER_ID.set(None)
|
222
|
+
|
223
|
+
# Convenience functions for different log types
|
224
|
+
def log_agent_action(agent_name: str, action: str, details: Optional[Dict[str, Any]] = None):
|
225
|
+
"""Log an agent action with structured data"""
|
226
|
+
logger = get_logger('agent.action', agent_name)
|
227
|
+
details_str = f" {details}" if details else ""
|
228
|
+
logger.info(f"{action}{details_str}")
|
229
|
+
|
230
|
+
def log_skill_event(agent_name: str, skill_name: str, event: str, details: Optional[Dict[str, Any]] = None):
|
231
|
+
"""Log a skill event"""
|
232
|
+
logger = get_logger(f'skill.{skill_name}', agent_name)
|
233
|
+
details_str = f" {details}" if details else ""
|
234
|
+
logger.info(f"{event}{details_str}")
|
235
|
+
|
236
|
+
def log_tool_execution(agent_name: str, tool_name: str, duration_ms: int, success: bool = True):
|
237
|
+
"""Log tool execution with timing"""
|
238
|
+
logger = get_logger('tool.execution', agent_name)
|
239
|
+
status = "SUCCESS" if success else "FAILED"
|
240
|
+
logger.info(f"Tool {tool_name} {status} ({duration_ms}ms)")
|
241
|
+
|
242
|
+
def log_handoff(agent_name: str, handoff_type: str, target: str, success: bool = True):
|
243
|
+
"""Log handoff execution"""
|
244
|
+
logger = get_logger('handoff', agent_name)
|
245
|
+
status = "SUCCESS" if success else "FAILED"
|
246
|
+
logger.info(f"Handoff {handoff_type} -> {target} {status}")
|
247
|
+
|
248
|
+
def log_server_request(endpoint: str, method: str, status_code: int, duration_ms: int, agent_name: Optional[str] = None):
|
249
|
+
"""Log server request with timing"""
|
250
|
+
logger = get_logger('server.request', agent_name)
|
251
|
+
logger.info(f"{method} {endpoint} {status_code} ({duration_ms}ms)")
|
252
|
+
|
253
|
+
# Performance logging utilities
|
254
|
+
class LogTimer:
|
255
|
+
"""Context manager for timing operations with automatic logging"""
|
256
|
+
|
257
|
+
def __init__(self, operation_name: str, logger: logging.Logger, level: int = logging.INFO):
|
258
|
+
self.operation_name = operation_name
|
259
|
+
self.logger = logger
|
260
|
+
self.level = level
|
261
|
+
self.start_time = None
|
262
|
+
|
263
|
+
def __enter__(self):
|
264
|
+
self.start_time = time.time()
|
265
|
+
self.logger.log(self.level, f"Starting {self.operation_name}")
|
266
|
+
return self
|
267
|
+
|
268
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
269
|
+
duration_ms = int((time.time() - self.start_time) * 1000)
|
270
|
+
if exc_type:
|
271
|
+
self.logger.error(f"{self.operation_name} FAILED ({duration_ms}ms): {exc_val}")
|
272
|
+
else:
|
273
|
+
self.logger.log(self.level, f"{self.operation_name} completed ({duration_ms}ms)")
|
274
|
+
|
275
|
+
def timer(operation_name: str, agent_name: Optional[str] = None, level: int = logging.INFO):
|
276
|
+
"""Create a timing context manager"""
|
277
|
+
logger = get_logger('performance', agent_name)
|
278
|
+
return LogTimer(operation_name, logger, level)
|
279
|
+
|
280
|
+
def configure_external_logger(logger_name: str, level: Optional[str] = None) -> None:
|
281
|
+
"""Configure an external logger to use our structured format
|
282
|
+
|
283
|
+
Args:
|
284
|
+
logger_name: Name of the logger to configure (e.g., 'litellm', 'openlicense')
|
285
|
+
level: Optional log level to set (defaults to current root level)
|
286
|
+
"""
|
287
|
+
logger = logging.getLogger(logger_name)
|
288
|
+
|
289
|
+
# Clear any existing handlers
|
290
|
+
logger.handlers.clear()
|
291
|
+
|
292
|
+
# Get the current root level if not specified
|
293
|
+
if level is None:
|
294
|
+
root_logger = logging.getLogger('robutler')
|
295
|
+
numeric_level = root_logger.level
|
296
|
+
else:
|
297
|
+
numeric_level = getattr(logging, level.upper(), logging.INFO)
|
298
|
+
|
299
|
+
# Add our formatted handler
|
300
|
+
handler = logging.StreamHandler(sys.stdout)
|
301
|
+
handler.setFormatter(RobutlerFormatter())
|
302
|
+
handler.setLevel(numeric_level)
|
303
|
+
logger.addHandler(handler)
|
304
|
+
logger.setLevel(numeric_level)
|
305
|
+
logger.propagate = False
|
306
|
+
|
307
|
+
def capture_all_loggers() -> None:
|
308
|
+
"""Ensure all existing loggers use our structured format
|
309
|
+
|
310
|
+
This function should be called after all modules are imported
|
311
|
+
to ensure any dynamically created loggers are properly configured.
|
312
|
+
"""
|
313
|
+
root_formatter = RobutlerFormatter()
|
314
|
+
root_level = logging.getLogger('robutler').level
|
315
|
+
|
316
|
+
# Get all existing loggers
|
317
|
+
for name in logging.Logger.manager.loggerDict:
|
318
|
+
logger = logging.getLogger(name)
|
319
|
+
|
320
|
+
# Skip if it's already a robutler logger
|
321
|
+
if name.startswith('robutler'):
|
322
|
+
continue
|
323
|
+
|
324
|
+
# Skip if it has handlers (already configured)
|
325
|
+
if logger.handlers:
|
326
|
+
# Update handlers to use our formatter
|
327
|
+
for handler in logger.handlers:
|
328
|
+
if isinstance(handler, logging.StreamHandler):
|
329
|
+
handler.setFormatter(root_formatter)
|
330
|
+
else:
|
331
|
+
# Add our handler if no handlers exist
|
332
|
+
handler = logging.StreamHandler(sys.stdout)
|
333
|
+
handler.setFormatter(root_formatter)
|
334
|
+
handler.setLevel(root_level)
|
335
|
+
logger.addHandler(handler)
|
336
|
+
logger.propagate = False
|
337
|
+
|
338
|
+
# Custom logger class that automatically uses our formatter
|
339
|
+
class RobutlerLogger(logging.Logger):
|
340
|
+
"""Custom logger that automatically gets our formatter"""
|
341
|
+
|
342
|
+
def __init__(self, name):
|
343
|
+
super().__init__(name)
|
344
|
+
# Automatically add our handler if this is a new logger
|
345
|
+
if not self.handlers and not name.startswith('robutler'):
|
346
|
+
handler = logging.StreamHandler(sys.stdout)
|
347
|
+
handler.setFormatter(RobutlerFormatter())
|
348
|
+
# Get the root level
|
349
|
+
root_level = logging.getLogger('robutler').level if logging.getLogger('robutler').level else logging.INFO
|
350
|
+
handler.setLevel(root_level)
|
351
|
+
self.addHandler(handler)
|
352
|
+
self.setLevel(root_level)
|
353
|
+
self.propagate = False
|
354
|
+
|
355
|
+
# Set our custom logger class as the default
|
356
|
+
logging.setLoggerClass(RobutlerLogger)
|
357
|
+
|
358
|
+
# Initialize logging on import (can be reconfigured later)
|
359
|
+
setup_logging()
|
@@ -0,0 +1,99 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: webagents
|
3
|
+
Version: 0.1.12
|
4
|
+
Summary: Web AI Agents SDK
|
5
|
+
Author: Awesome Opensource Contributors and Robutler Team
|
6
|
+
License: TBD
|
7
|
+
License-File: LICENSE
|
8
|
+
Requires-Python: >=3.10
|
9
|
+
Requires-Dist: colorama>=0.4.6
|
10
|
+
Requires-Dist: fastapi>=0.100.0
|
11
|
+
Requires-Dist: fastmcp>=2.3.0
|
12
|
+
Requires-Dist: httpx>=0.24.0
|
13
|
+
Requires-Dist: litellm>=1.0.0
|
14
|
+
Requires-Dist: pillow>=10.0.0
|
15
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
16
|
+
Requires-Dist: pydantic>=2.7.0
|
17
|
+
Requires-Dist: python-dotenv>=1.0.0
|
18
|
+
Requires-Dist: tiktoken>=0.5.0
|
19
|
+
Requires-Dist: uvicorn>=0.23.0
|
20
|
+
Provides-Extra: dev
|
21
|
+
Requires-Dist: black>=23.0.0; extra == 'dev'
|
22
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
23
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
24
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
25
|
+
Requires-Dist: ruff>=0.0.270; extra == 'dev'
|
26
|
+
Provides-Extra: examples
|
27
|
+
Requires-Dist: openai-agents>=0.0.16; extra == 'examples'
|
28
|
+
Description-Content-Type: text/markdown
|
29
|
+
|
30
|
+
# Robutler
|
31
|
+
|
32
|
+
Build discoverable and monetizable AI agents.
|
33
|
+
|
34
|
+
|
35
|
+
## Installation
|
36
|
+
|
37
|
+
```bash
|
38
|
+
pip install robutler
|
39
|
+
```
|
40
|
+
|
41
|
+
## Quick Start
|
42
|
+
|
43
|
+
### AI Agent Server
|
44
|
+
|
45
|
+
Create AI agents with OpenAI-compatible endpoints:
|
46
|
+
|
47
|
+
```python
|
48
|
+
from robutler.server import RobutlerServer, pricing
|
49
|
+
from robutler.agent import RobutlerAgent
|
50
|
+
|
51
|
+
# Create tools with pricing
|
52
|
+
@pricing(credits_per_call=100)
|
53
|
+
def get_weather(location: str) -> str:
|
54
|
+
"""Get current weather for a location"""
|
55
|
+
return f"Weather in {location}: Sunny, 72°F"
|
56
|
+
|
57
|
+
# Create an agent with intents
|
58
|
+
agent = RobutlerAgent(
|
59
|
+
name="assistant",
|
60
|
+
instructions="You are a helpful AI assistant.",
|
61
|
+
credits_per_token=5,
|
62
|
+
model="gpt-4o-mini",
|
63
|
+
tools=[get_weather],
|
64
|
+
intents=["help with weather", "provide assistance", "answer questions"]
|
65
|
+
)
|
66
|
+
|
67
|
+
# Create server with automatic endpoint creation
|
68
|
+
app = RobutlerServer(agents=[agent])
|
69
|
+
|
70
|
+
# Endpoints are automatically created:
|
71
|
+
# POST /assistant/chat/completions - OpenAI-compatible chat
|
72
|
+
# GET /assistant - Agent info
|
73
|
+
```
|
74
|
+
|
75
|
+
Run the server:
|
76
|
+
|
77
|
+
```bash
|
78
|
+
uvicorn main:app --host 0.0.0.0 --port 8000
|
79
|
+
```
|
80
|
+
|
81
|
+
### API Client
|
82
|
+
|
83
|
+
```python
|
84
|
+
from robutler.api import RobutlerApi
|
85
|
+
|
86
|
+
async with RobutlerApi() as api:
|
87
|
+
user = await api.get_user_info()
|
88
|
+
credits = await api.get_user_credits()
|
89
|
+
```
|
90
|
+
|
91
|
+
## Documentation
|
92
|
+
|
93
|
+
For comprehensive documentation, visit: [docs.robutler.ai](https://docs.robutler.ai)
|
94
|
+
|
95
|
+
## Environment Variables
|
96
|
+
|
97
|
+
```bash
|
98
|
+
ROBUTLER_API_KEY=your_api_key
|
99
|
+
```
|
@@ -0,0 +1,96 @@
|
|
1
|
+
webagents/__init__.py,sha256=81hdVapJ4bFsW9H_jpnuFFw7yn5UdHBxhy07ELy1skE,373
|
2
|
+
webagents/agents/__init__.py,sha256=JkRjxf5lqVrBNjbV40zdKUGKmv-QKT18Obo1pHZDiPU,244
|
3
|
+
webagents/agents/core/__init__.py,sha256=H_Pj76OywpsztZmcmptmJKAluRue3KK3kMnc1xKXlWg,541
|
4
|
+
webagents/agents/core/base_agent.py,sha256=BPpUxfLOJ3CLU0uDfghDVVyx8oPw72lX1REviuCvFlQ,93798
|
5
|
+
webagents/agents/core/handoffs.py,sha256=1IUIIXPAGzidLRa6vNBgkgEZEP8xFD97quuOZKu5xIg,11075
|
6
|
+
webagents/agents/handoffs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
webagents/agents/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
webagents/agents/lifecycle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
webagents/agents/skills/__init__.py,sha256=adsMcCrrzfvRd3DHLhtjyml2zJ5qsMajI0IpAR1B1pk,3199
|
10
|
+
webagents/agents/skills/base.py,sha256=76kYfbxTfT60MMeeTIiANWSXRhdd01OazbTnP1rkGQ4,5098
|
11
|
+
webagents/agents/skills/core/__init__.py,sha256=xT_-sPnLbxTUqjvg0toVCqQyB6OP-An_vBprdv_t0xA,258
|
12
|
+
webagents/agents/skills/core/guardrails/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
webagents/agents/skills/core/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
+
webagents/agents/skills/core/llm/anthropic/__init__.py,sha256=NkitGyW7aAdDPKsIeZaU979us3yg84Hej1L_Ogtw-f8,68
|
15
|
+
webagents/agents/skills/core/llm/litellm/__init__.py,sha256=IEvhO15GW1naAPGizpJc6wjMtzf9As13WLVKMKevUc8,271
|
16
|
+
webagents/agents/skills/core/llm/litellm/skill.py,sha256=nbeI7xnXt3YN9X4IdhqPA3KCKiCxP_ilEewWBisbg-Q,22266
|
17
|
+
webagents/agents/skills/core/llm/openai/__init__.py,sha256=eHvy20Z-geoVAZu8MstRiPXsEXZLJcBq3GtSZSLeOXo,65
|
18
|
+
webagents/agents/skills/core/llm/xai/__init__.py,sha256=HPcn0Ki-Di0kIzV5bvb-Vt-8vGW-ufBmHI9ZBeIdlA8,62
|
19
|
+
webagents/agents/skills/core/mcp/README.md,sha256=5uHOYvBR0XtTHCl4ZN4rZ5KA4-skLlb51KDGMeQOuk8,14948
|
20
|
+
webagents/agents/skills/core/mcp/__init__.py,sha256=0dBqPqObN8kREXP28fX-ANxxyf6NFol_n95TgxTYkjU,366
|
21
|
+
webagents/agents/skills/core/mcp/skill.py,sha256=sS7V5PUTKf0eRGBX3VP-6Rt2dyNnwR7wPjclXbGg8t8,30252
|
22
|
+
webagents/agents/skills/core/memory/__init__.py,sha256=EH3YM_WQ9GZcgJnbxfB5UaKZj6VU3a9k8pD-GcLnExI,328
|
23
|
+
webagents/agents/skills/core/memory/long_term_memory/__init__.py,sha256=Bk4DChm7NDLizK0yS-NBWTA7FWSc_SSVYI80F_BJ6MU,258
|
24
|
+
webagents/agents/skills/core/memory/long_term_memory/memory_skill.py,sha256=6SAFPcN0VNzL1b1k-v29eHeF10EIC8uYsKJ8v5PUFA0,24053
|
25
|
+
webagents/agents/skills/core/memory/short_term_memory/__init__.py,sha256=c9N68CZFCFyc5emkauutc2JNIKrN76emz4loDqVbzzo,216
|
26
|
+
webagents/agents/skills/core/memory/short_term_memory/skill.py,sha256=OkgGkfhC8cth-Py2HmneZOW426cHjhBzKto8KhvrPKI,12790
|
27
|
+
webagents/agents/skills/core/memory/vector_memory/skill.py,sha256=ZvqftsLyyIa59gESjAItjdgLG8G5SlPM8G2Su2q0xqw,19997
|
28
|
+
webagents/agents/skills/core/planning/__init__.py,sha256=vGmkhbYvVD2DFtZAKBLqhgG1qwQz0soxijGjk0u8Pr0,222
|
29
|
+
webagents/agents/skills/core/planning/planner.py,sha256=EFBH9vrYcYaWgXSlC0c8nUP9eGj6b_RyZ4dHbNjFVXU,13900
|
30
|
+
webagents/agents/skills/ecosystem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
+
webagents/agents/skills/ecosystem/crewai/__init__.py,sha256=MfHsOOPpXVUWcXyiip2_svHF8YxrJ60cH28TM8ef__Q,30
|
32
|
+
webagents/agents/skills/ecosystem/database/__init__.py,sha256=x2y6F1FCplEmLaUXKztNDtNg_o1Y61ttiH1EiSrqCJ0,32
|
33
|
+
webagents/agents/skills/ecosystem/filesystem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
|
+
webagents/agents/skills/ecosystem/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
+
webagents/agents/skills/ecosystem/google/calendar/__init__.py,sha256=s_e6EPc07c-iO06BUYaVyat1arGkNBLt29BKHubL6-0,77
|
36
|
+
webagents/agents/skills/ecosystem/google/calendar/skill.py,sha256=2yRiornRfF7kfFOO_IbkQpeYdzFRBzceTsMXg0ub25g,15622
|
37
|
+
webagents/agents/skills/ecosystem/n8n/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
+
webagents/agents/skills/ecosystem/openai_agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
+
webagents/agents/skills/ecosystem/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
|
+
webagents/agents/skills/ecosystem/zapier/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
|
+
webagents/agents/skills/robutler/__init__.py,sha256=H2qNyHj358HnsdAtjfdvtPX0VIr5Rb_X6ExLtxqe3V8,164
|
42
|
+
webagents/agents/skills/robutler/storage.py,sha256=Q_L6YZvf98l7RBQqVYNKeur3U9LLZqZe2WkNObJX5RA,14684
|
43
|
+
webagents/agents/skills/robutler/auth/README.md,sha256=mRcuGF3ty3WyoMCwR0pxYnOWNOKyM7h5MW67-9Y3V4M,2556
|
44
|
+
webagents/agents/skills/robutler/auth/__init__.py,sha256=ch56w3JbDv2nQfdFmMV_HBoysJnJ17vFgc-XoPtCrXs,449
|
45
|
+
webagents/agents/skills/robutler/auth/skill.py,sha256=5qZhmsvohfhQGp4WOLdqV16UJOvnwoeXZHyq_vyTMzk,14819
|
46
|
+
webagents/agents/skills/robutler/crm/__init__.py,sha256=A0A4KxlJauzsfmlB9KRoqWorQ18PxHGeSb1jGP-pKLY,335
|
47
|
+
webagents/agents/skills/robutler/crm/skill.py,sha256=8yGheWkLoYrWmDti-zMKcI_SlTIqAZtgiGMTQaOlJJA,12949
|
48
|
+
webagents/agents/skills/robutler/discovery/README.md,sha256=GvLvi6VZSGkrBBYahtktnl1AUWVNQ7gf6NTfUlMtuuQ,9188
|
49
|
+
webagents/agents/skills/robutler/discovery/__init__.py,sha256=lWcOz75Ap7M2Fjno3eycYHjwmm8nL4_J3_6JbIfESGg,317
|
50
|
+
webagents/agents/skills/robutler/discovery/skill.py,sha256=TCJrsLR865z9iiFRVtB-_qO7i2XnqkNKxhkZzMYukDQ,9303
|
51
|
+
webagents/agents/skills/robutler/kv/__init__.py,sha256=sbaE6gr_OksCWIhJE0kFMpFErAHUnW_7coW8HiKePM8,53
|
52
|
+
webagents/agents/skills/robutler/kv/skill.py,sha256=ftZulx4gQD9lQVstCTj7ZjsWML2XcZ6PU-2lSGpePHU,3364
|
53
|
+
webagents/agents/skills/robutler/message_history/__init__.py,sha256=o8SVUowaFtDtVPScDy1BG650mT87_-MI_1IqkB8eUJA,213
|
54
|
+
webagents/agents/skills/robutler/message_history/skill.py,sha256=6GEdhZx4MwZqvjU_bmo6eu3ZmOd1USNhJuuHmMAFgyA,11176
|
55
|
+
webagents/agents/skills/robutler/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
|
+
webagents/agents/skills/robutler/nli/__init__.py,sha256=7N_RC2Pp00BFH3brNeUXEFbVhjQjARAIKM8Ep-axeHY,309
|
57
|
+
webagents/agents/skills/robutler/nli/skill.py,sha256=zzEqTeUiA4YzhyiyuLVnFsGzglDocc6UZzTZMxU5_o4,30598
|
58
|
+
webagents/agents/skills/robutler/notifications/__init__.py,sha256=N5ZWC0YkDRpKsIlazlVdYLBDMvhFg3s1ZIOzpi75EJg,74
|
59
|
+
webagents/agents/skills/robutler/notifications/skill.py,sha256=uJpAoCWh0XR475tPhETEePhu0RzvDSxz9cDH2SC7-qQ,5576
|
60
|
+
webagents/agents/skills/robutler/payments/__init__.py,sha256=w2hRAnGDQ29S_fxIKitJ6BM9pPe9TVYn0DfQYjaPYM4,1109
|
61
|
+
webagents/agents/skills/robutler/payments/exceptions.py,sha256=x2Wqu53D-INry2MH4dULUpBgnK24FEGC1bGcO3aI2VM,9696
|
62
|
+
webagents/agents/skills/robutler/payments/skill.py,sha256=Kaamttu19iTWjSpgS79mzXv0pqAXgrATrYvz50fZ26o,27859
|
63
|
+
webagents/agents/skills/robutler/storage/__init__.py,sha256=79t768tWloke6VSZWWy22T5IXWn3nvQCI1WM8mJA4fA,225
|
64
|
+
webagents/agents/skills/robutler/storage/files/__init__.py,sha256=00BpB6z2eJu05Gs6s5hN3Qzhb2InbQUX3uGuJ2Zs2tk,200
|
65
|
+
webagents/agents/skills/robutler/storage/files/skill.py,sha256=v9iJDbMUcJfZjdhsl6ufvpcMx28hqUY7_h16Sr_-FXU,19302
|
66
|
+
webagents/agents/skills/robutler/storage/json/__init__.py,sha256=bLyAhYxHLTkfg-CuHysiANI0UabqnN4BeSdC7ey1isg,188
|
67
|
+
webagents/agents/skills/robutler/storage/json/skill.py,sha256=d3u_apjCrS4fokXKLK_hWnbchRoBaYsFfQRfDTIh1X4,12423
|
68
|
+
webagents/agents/skills/robutler/storage/kv/skill.py,sha256=c-UqWT-v6Xpx3DYTCxy78U7Q0cC-VlFYoTekBdP4OPg,3347
|
69
|
+
webagents/agents/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
70
|
+
webagents/agents/tools/decorators.py,sha256=yma0Q0yMglJYDF2hSKza0j0O6UoiWXyOywet36UDjq8,17151
|
71
|
+
webagents/agents/tracing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
72
|
+
webagents/agents/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
73
|
+
webagents/api/__init__.py,sha256=iSNQA260QMfGcMQhXTWE5oPrIdXjxpyTwVCSn_06Im4,400
|
74
|
+
webagents/api/client.py,sha256=pit48wgXkFMYn3RkIjGQ84ZWuvRiG-dlWkrr2lAgNkI,51712
|
75
|
+
webagents/api/types.py,sha256=x6L6Haxx7Nutxmp6WgNKjwyfF1mHxozfazye7YEq4zo,7582
|
76
|
+
webagents/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
77
|
+
webagents/server/__init__.py,sha256=7dpB8oYWeGvxVo3kXv-us7dAE6BMlUlZOqymAuBfMGM,606
|
78
|
+
webagents/server/middleware.py,sha256=CihiHnpPdW406SIZtxy3ewbCHHMcLO_5cAwgLQRwdzQ,12067
|
79
|
+
webagents/server/models.py,sha256=ncMD7I_NVMNAD2CkuRokHFH0xLw23ZVDZlcHyOpV83c,4800
|
80
|
+
webagents/server/monitoring.py,sha256=u-DbqU4dOFGYiSPlsC-6e1vr_JHw0Qe-amav_tv4ar4,20446
|
81
|
+
webagents/server/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
82
|
+
webagents/server/context/context_vars.py,sha256=dPZqQPClYdwFrLI_oMtVBw_eglnkbVdiArHMxSDSVCE,3613
|
83
|
+
webagents/server/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
84
|
+
webagents/server/core/app.py,sha256=YG_uFzca9FKRbs_IxxEMbqJ9XGnQuZXVmWnE3K6Q700,38455
|
85
|
+
webagents/server/core/middleware.py,sha256=i5OmQCtuDKe_V1Z3cVSWn5TsEpo_K1CmiHNjmDHidMA,2225
|
86
|
+
webagents/server/core/models.py,sha256=w4KFjulstrdbojf4zaRj3k_wtATZMHZVAFX0XalJ6Sk,4674
|
87
|
+
webagents/server/core/monitoring.py,sha256=j6fKkKgb-vRZX3fxT5FzcNGzPK7ykws3D1R9lXjQdVQ,1523
|
88
|
+
webagents/server/endpoints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
89
|
+
webagents/server/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
|
+
webagents/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
91
|
+
webagents/utils/logging.py,sha256=F2Cfee7O_KgYvUIvuAqTZrkE8FXJ3_Zgvn-jR3rHC8Y,14057
|
92
|
+
webagents-0.1.12.dist-info/METADATA,sha256=NFP0dW63rBfma3WdAXKjys2NNR2rQQP6Cft5Q2w4FbU,2372
|
93
|
+
webagents-0.1.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
94
|
+
webagents-0.1.12.dist-info/entry_points.txt,sha256=bITAYBK8-H8EQUrDctEeEKuer4jAp3lfxKfvH5TT1eM,54
|
95
|
+
webagents-0.1.12.dist-info/licenses/LICENSE,sha256=A2JlSaWav2SO5ZFjs7isv2bDZRPLHnbW4ne8BEySbjA,3
|
96
|
+
webagents-0.1.12.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
TBD
|