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.
Files changed (96) hide show
  1. webagents/__init__.py +18 -0
  2. webagents/agents/__init__.py +13 -0
  3. webagents/agents/core/__init__.py +19 -0
  4. webagents/agents/core/base_agent.py +1834 -0
  5. webagents/agents/core/handoffs.py +293 -0
  6. webagents/agents/handoffs/__init__.py +0 -0
  7. webagents/agents/interfaces/__init__.py +0 -0
  8. webagents/agents/lifecycle/__init__.py +0 -0
  9. webagents/agents/skills/__init__.py +109 -0
  10. webagents/agents/skills/base.py +136 -0
  11. webagents/agents/skills/core/__init__.py +8 -0
  12. webagents/agents/skills/core/guardrails/__init__.py +0 -0
  13. webagents/agents/skills/core/llm/__init__.py +0 -0
  14. webagents/agents/skills/core/llm/anthropic/__init__.py +1 -0
  15. webagents/agents/skills/core/llm/litellm/__init__.py +10 -0
  16. webagents/agents/skills/core/llm/litellm/skill.py +538 -0
  17. webagents/agents/skills/core/llm/openai/__init__.py +1 -0
  18. webagents/agents/skills/core/llm/xai/__init__.py +1 -0
  19. webagents/agents/skills/core/mcp/README.md +375 -0
  20. webagents/agents/skills/core/mcp/__init__.py +15 -0
  21. webagents/agents/skills/core/mcp/skill.py +731 -0
  22. webagents/agents/skills/core/memory/__init__.py +11 -0
  23. webagents/agents/skills/core/memory/long_term_memory/__init__.py +10 -0
  24. webagents/agents/skills/core/memory/long_term_memory/memory_skill.py +639 -0
  25. webagents/agents/skills/core/memory/short_term_memory/__init__.py +9 -0
  26. webagents/agents/skills/core/memory/short_term_memory/skill.py +341 -0
  27. webagents/agents/skills/core/memory/vector_memory/skill.py +447 -0
  28. webagents/agents/skills/core/planning/__init__.py +9 -0
  29. webagents/agents/skills/core/planning/planner.py +343 -0
  30. webagents/agents/skills/ecosystem/__init__.py +0 -0
  31. webagents/agents/skills/ecosystem/crewai/__init__.py +1 -0
  32. webagents/agents/skills/ecosystem/database/__init__.py +1 -0
  33. webagents/agents/skills/ecosystem/filesystem/__init__.py +0 -0
  34. webagents/agents/skills/ecosystem/google/__init__.py +0 -0
  35. webagents/agents/skills/ecosystem/google/calendar/__init__.py +6 -0
  36. webagents/agents/skills/ecosystem/google/calendar/skill.py +306 -0
  37. webagents/agents/skills/ecosystem/n8n/__init__.py +0 -0
  38. webagents/agents/skills/ecosystem/openai_agents/__init__.py +0 -0
  39. webagents/agents/skills/ecosystem/web/__init__.py +0 -0
  40. webagents/agents/skills/ecosystem/zapier/__init__.py +0 -0
  41. webagents/agents/skills/robutler/__init__.py +11 -0
  42. webagents/agents/skills/robutler/auth/README.md +63 -0
  43. webagents/agents/skills/robutler/auth/__init__.py +17 -0
  44. webagents/agents/skills/robutler/auth/skill.py +354 -0
  45. webagents/agents/skills/robutler/crm/__init__.py +18 -0
  46. webagents/agents/skills/robutler/crm/skill.py +368 -0
  47. webagents/agents/skills/robutler/discovery/README.md +281 -0
  48. webagents/agents/skills/robutler/discovery/__init__.py +16 -0
  49. webagents/agents/skills/robutler/discovery/skill.py +230 -0
  50. webagents/agents/skills/robutler/kv/__init__.py +6 -0
  51. webagents/agents/skills/robutler/kv/skill.py +80 -0
  52. webagents/agents/skills/robutler/message_history/__init__.py +9 -0
  53. webagents/agents/skills/robutler/message_history/skill.py +270 -0
  54. webagents/agents/skills/robutler/messages/__init__.py +0 -0
  55. webagents/agents/skills/robutler/nli/__init__.py +13 -0
  56. webagents/agents/skills/robutler/nli/skill.py +687 -0
  57. webagents/agents/skills/robutler/notifications/__init__.py +5 -0
  58. webagents/agents/skills/robutler/notifications/skill.py +141 -0
  59. webagents/agents/skills/robutler/payments/__init__.py +41 -0
  60. webagents/agents/skills/robutler/payments/exceptions.py +255 -0
  61. webagents/agents/skills/robutler/payments/skill.py +610 -0
  62. webagents/agents/skills/robutler/storage/__init__.py +10 -0
  63. webagents/agents/skills/robutler/storage/files/__init__.py +9 -0
  64. webagents/agents/skills/robutler/storage/files/skill.py +445 -0
  65. webagents/agents/skills/robutler/storage/json/__init__.py +9 -0
  66. webagents/agents/skills/robutler/storage/json/skill.py +336 -0
  67. webagents/agents/skills/robutler/storage/kv/skill.py +88 -0
  68. webagents/agents/skills/robutler/storage.py +389 -0
  69. webagents/agents/tools/__init__.py +0 -0
  70. webagents/agents/tools/decorators.py +426 -0
  71. webagents/agents/tracing/__init__.py +0 -0
  72. webagents/agents/workflows/__init__.py +0 -0
  73. webagents/api/__init__.py +17 -0
  74. webagents/api/client.py +1207 -0
  75. webagents/api/types.py +253 -0
  76. webagents/scripts/__init__.py +0 -0
  77. webagents/server/__init__.py +28 -0
  78. webagents/server/context/__init__.py +0 -0
  79. webagents/server/context/context_vars.py +121 -0
  80. webagents/server/core/__init__.py +0 -0
  81. webagents/server/core/app.py +843 -0
  82. webagents/server/core/middleware.py +69 -0
  83. webagents/server/core/models.py +98 -0
  84. webagents/server/core/monitoring.py +59 -0
  85. webagents/server/endpoints/__init__.py +0 -0
  86. webagents/server/interfaces/__init__.py +0 -0
  87. webagents/server/middleware.py +330 -0
  88. webagents/server/models.py +92 -0
  89. webagents/server/monitoring.py +659 -0
  90. webagents/utils/__init__.py +0 -0
  91. webagents/utils/logging.py +359 -0
  92. webagents-0.1.12.dist-info/METADATA +99 -0
  93. webagents-0.1.12.dist-info/RECORD +96 -0
  94. webagents-0.1.12.dist-info/WHEEL +4 -0
  95. webagents-0.1.12.dist-info/entry_points.txt +2 -0
  96. webagents-0.1.12.dist-info/licenses/LICENSE +1 -0
webagents/api/types.py ADDED
@@ -0,0 +1,253 @@
1
+ """
2
+ Robutler API Types - Robutler V2.0
3
+
4
+ Data types and models for Robutler Platform API integration.
5
+ Based on the Robutler Portal database schema.
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+ from datetime import datetime
10
+ from typing import Dict, Any, List, Optional
11
+ from decimal import Decimal
12
+ from enum import Enum
13
+
14
+
15
+ class UserRole(Enum):
16
+ """User role enumeration"""
17
+ USER = "user"
18
+ ADMIN = "admin"
19
+
20
+
21
+ class SubscriptionStatus(Enum):
22
+ """Subscription status enumeration"""
23
+ ACTIVE = "active"
24
+ INACTIVE = "inactive"
25
+ CANCELED = "canceled"
26
+ TRIALING = "trialing"
27
+ PAST_DUE = "past_due"
28
+
29
+
30
+ class IntegrationType(Enum):
31
+ """Integration type enumeration"""
32
+ AGENT = "agent"
33
+ MCP = "mcp"
34
+ API = "api"
35
+
36
+
37
+ class IntegrationProtocol(Enum):
38
+ """Integration protocol enumeration"""
39
+ MCP = "mcp"
40
+ A2A = "a2a"
41
+ P2PMCP = "p2pmcp"
42
+ HTTP = "http"
43
+
44
+
45
+ class TransactionType(Enum):
46
+ """Credit transaction type enumeration"""
47
+ ADDITION = "addition"
48
+ USAGE = "usage"
49
+ TRANSFER = "transfer"
50
+
51
+
52
+ @dataclass
53
+ class User:
54
+ """Robutler platform user"""
55
+ id: str
56
+ name: Optional[str] = None
57
+ email: str = ""
58
+ role: UserRole = UserRole.USER
59
+ google_id: Optional[str] = None
60
+ avatar_url: Optional[str] = None
61
+ created_at: Optional[datetime] = None
62
+ updated_at: Optional[datetime] = None
63
+ # Stripe/Payment fields
64
+ stripe_customer_id: Optional[str] = None
65
+ stripe_subscription_id: Optional[str] = None
66
+ stripe_product_id: Optional[str] = None
67
+ plan_name: Optional[str] = None
68
+ subscription_status: Optional[SubscriptionStatus] = None
69
+ # Credits
70
+ total_credits: Decimal = Decimal('0')
71
+ used_credits: Decimal = Decimal('0')
72
+ # Referrals
73
+ referral_code: Optional[str] = None
74
+ referred_by: Optional[str] = None
75
+ referral_count: int = 0
76
+
77
+ @property
78
+ def available_credits(self) -> Decimal:
79
+ """Calculate available credits"""
80
+ return self.total_credits - self.used_credits
81
+
82
+ @property
83
+ def is_admin(self) -> bool:
84
+ """Check if user is admin"""
85
+ return self.role == UserRole.ADMIN
86
+
87
+ def to_dict(self) -> Dict[str, Any]:
88
+ """Convert to dictionary"""
89
+ return {
90
+ 'id': self.id,
91
+ 'name': self.name,
92
+ 'email': self.email,
93
+ 'role': self.role.value,
94
+ 'avatar_url': self.avatar_url,
95
+ 'total_credits': str(self.total_credits),
96
+ 'used_credits': str(self.used_credits),
97
+ 'available_credits': str(self.available_credits),
98
+ 'subscription_status': self.subscription_status.value if self.subscription_status else None,
99
+ 'plan_name': self.plan_name,
100
+ 'referral_code': self.referral_code,
101
+ 'is_admin': self.is_admin
102
+ }
103
+
104
+
105
+ @dataclass
106
+ class ApiKey:
107
+ """Robutler platform API key"""
108
+ id: str
109
+ user_id: str
110
+ name: str
111
+ key_hash: str
112
+ last_used: Optional[datetime] = None
113
+ expires_at: Optional[datetime] = None
114
+ is_active: bool = True
115
+ daily_rate_limit: Optional[int] = None
116
+ daily_credit_limit: Optional[Decimal] = None
117
+ session_credit_limit: Optional[Decimal] = None
118
+ spent_credits: Decimal = Decimal('0')
119
+ earned_credits: Decimal = Decimal('0')
120
+ permissions: Optional[Dict[str, Any]] = None
121
+ integration_id: Optional[str] = None
122
+ created_at: Optional[datetime] = None
123
+ updated_at: Optional[datetime] = None
124
+
125
+ @property
126
+ def is_expired(self) -> bool:
127
+ """Check if API key is expired"""
128
+ if not self.expires_at:
129
+ return False
130
+ return datetime.utcnow() > self.expires_at
131
+
132
+ @property
133
+ def is_valid(self) -> bool:
134
+ """Check if API key is valid"""
135
+ return self.is_active and not self.is_expired
136
+
137
+ def to_dict(self) -> Dict[str, Any]:
138
+ """Convert to dictionary"""
139
+ return {
140
+ 'id': self.id,
141
+ 'user_id': self.user_id,
142
+ 'name': self.name,
143
+ 'is_active': self.is_active,
144
+ 'is_expired': self.is_expired,
145
+ 'is_valid': self.is_valid,
146
+ 'expires_at': self.expires_at.isoformat() if self.expires_at else None,
147
+ 'last_used': self.last_used.isoformat() if self.last_used else None,
148
+ 'daily_credit_limit': str(self.daily_credit_limit) if self.daily_credit_limit else None,
149
+ 'session_credit_limit': str(self.session_credit_limit) if self.session_credit_limit else None,
150
+ 'spent_credits': str(self.spent_credits),
151
+ 'permissions': self.permissions
152
+ }
153
+
154
+
155
+ @dataclass
156
+ class Integration:
157
+ """Robutler platform integration"""
158
+ id: str
159
+ user_id: str
160
+ agent_id: Optional[str] = None
161
+ name: Optional[str] = None
162
+ type: IntegrationType = IntegrationType.API
163
+ protocol: IntegrationProtocol = IntegrationProtocol.HTTP
164
+ secret: Optional[str] = None
165
+ api_key_id: Optional[str] = None
166
+ created_at: Optional[datetime] = None
167
+ updated_at: Optional[datetime] = None
168
+
169
+ def to_dict(self) -> Dict[str, Any]:
170
+ """Convert to dictionary"""
171
+ return {
172
+ 'id': self.id,
173
+ 'user_id': self.user_id,
174
+ 'agent_id': self.agent_id,
175
+ 'name': self.name,
176
+ 'type': self.type.value,
177
+ 'protocol': self.protocol.value,
178
+ 'api_key_id': self.api_key_id,
179
+ 'created_at': self.created_at.isoformat() if self.created_at else None
180
+ }
181
+
182
+
183
+ @dataclass
184
+ class CreditTransaction:
185
+ """Robutler platform credit transaction"""
186
+ id: str
187
+ user_id: str
188
+ integration_id: Optional[str] = None
189
+ api_key_id: Optional[str] = None
190
+ recipient_id: Optional[str] = None
191
+ amount: Decimal = Decimal('0')
192
+ type: TransactionType = TransactionType.USAGE
193
+ source: str = "api_usage"
194
+ description: Optional[str] = None
195
+ receipt: Optional[str] = None
196
+ created_at: Optional[datetime] = None
197
+
198
+ def to_dict(self) -> Dict[str, Any]:
199
+ """Convert to dictionary"""
200
+ return {
201
+ 'id': self.id,
202
+ 'user_id': self.user_id,
203
+ 'integration_id': self.integration_id,
204
+ 'api_key_id': self.api_key_id,
205
+ 'amount': str(self.amount),
206
+ 'type': self.type.value,
207
+ 'source': self.source,
208
+ 'description': self.description,
209
+ 'created_at': self.created_at.isoformat() if self.created_at else None
210
+ }
211
+
212
+
213
+ @dataclass
214
+ class AuthResponse:
215
+ """Authentication response from Robutler API"""
216
+ success: bool
217
+ user: Optional[User] = None
218
+ api_key: Optional[ApiKey] = None
219
+ error: Optional[str] = None
220
+ message: Optional[str] = None
221
+
222
+ def to_dict(self) -> Dict[str, Any]:
223
+ """Convert to dictionary"""
224
+ result = {
225
+ 'success': self.success,
226
+ 'error': self.error,
227
+ 'message': self.message
228
+ }
229
+ if self.user:
230
+ result['user'] = self.user.to_dict()
231
+ if self.api_key:
232
+ result['api_key'] = self.api_key.to_dict()
233
+ return result
234
+
235
+
236
+ @dataclass
237
+ class ApiResponse:
238
+ """Generic API response from Robutler Platform"""
239
+ success: bool
240
+ data: Optional[Dict[str, Any]] = None
241
+ error: Optional[str] = None
242
+ message: Optional[str] = None
243
+ status_code: int = 200
244
+
245
+ def to_dict(self) -> Dict[str, Any]:
246
+ """Convert to dictionary"""
247
+ return {
248
+ 'success': self.success,
249
+ 'data': self.data,
250
+ 'error': self.error,
251
+ 'message': self.message,
252
+ 'status_code': self.status_code
253
+ }
File without changes
@@ -0,0 +1,28 @@
1
+ """
2
+ Robutler V2.0 Server Package
3
+
4
+ FastAPI server implementation with OpenAI compatibility,
5
+ streaming support, and comprehensive agent management.
6
+ """
7
+
8
+ # Import moved to avoid circular dependency
9
+ # from .core.app import RobutlerServer, create_server
10
+ from .models import (
11
+ ChatCompletionRequest,
12
+ OpenAIResponse,
13
+ OpenAIStreamChunk,
14
+ AgentInfoResponse,
15
+ ServerInfo,
16
+ HealthResponse
17
+ )
18
+
19
+ __all__ = [
20
+ # 'RobutlerServer',
21
+ # 'create_server',
22
+ 'ChatCompletionRequest',
23
+ 'OpenAIResponse',
24
+ 'OpenAIStreamChunk',
25
+ 'AgentInfoResponse',
26
+ 'ServerInfo',
27
+ 'HealthResponse'
28
+ ]
File without changes
@@ -0,0 +1,121 @@
1
+ """
2
+ Context Variables and Unified Context - Robutler V2.0
3
+
4
+ Unified context management using Python's contextvars for thread-safe,
5
+ async-compatible context handling.
6
+ """
7
+
8
+ import time
9
+ import uuid
10
+ from contextvars import ContextVar
11
+ from dataclasses import dataclass, field
12
+ from typing import Dict, Any, List, Optional, Union
13
+ from datetime import datetime
14
+
15
+
16
+ # Single ContextVar for unified context
17
+ CONTEXT: ContextVar['Context'] = ContextVar('robutler_context')
18
+
19
+
20
+ @dataclass
21
+ class Context:
22
+ """Unified Context containing ALL request data AND agent capabilities
23
+
24
+ This replaces the previous multiple context variables with a single,
25
+ comprehensive context object that contains everything skills and
26
+ tools need access to.
27
+ """
28
+
29
+ # Request identification
30
+ request_id: str = field(default_factory=lambda: str(uuid.uuid4()))
31
+ start_time: float = field(default_factory=time.time)
32
+
33
+ # Request data
34
+ messages: List[Dict[str, Any]] = field(default_factory=list)
35
+ stream: bool = False
36
+
37
+ agent: Optional[Any] = None # BaseAgent instance
38
+ request: Optional[Any] = None # Incoming HTTP request wrapper
39
+
40
+ # Authentication namespace (populated by AuthSkill)
41
+ auth: Optional[Any] = None
42
+
43
+ # Usage data
44
+ usage: List[Dict[str, Any]] = field(default_factory=list)
45
+
46
+ # Custom data storage (for skills/tools to store temporary data)
47
+ custom_data: Dict[str, Any] = field(default_factory=dict)
48
+
49
+ # --- Properties for clean access ---
50
+
51
+ @property
52
+ def skills(self) -> Dict[str, Any]:
53
+ """Access to agent's skills"""
54
+ return self.agent.skills if self.agent else {}
55
+
56
+ @property
57
+ def tools(self) -> List[Dict[str, Any]]:
58
+ """Access to agent's registered tools"""
59
+ return self.agent.get_all_tools() if self.agent else []
60
+
61
+ @property
62
+ def handoffs(self) -> List[Dict[str, Any]]:
63
+ """Access to agent's registered handoffs"""
64
+ return self.agent.get_all_handoffs() if self.agent else []
65
+
66
+ @property
67
+ def auth_scope(self) -> str:
68
+ """Determine user scope based on user context"""
69
+ return self.auth.scope.value if self.auth else 'all'
70
+
71
+ # --- Methods for data manipulation ---
72
+
73
+ def set(self, key: str, value: Any) -> None:
74
+ """Store custom data"""
75
+ self.custom_data[key] = value
76
+
77
+ def get(self, key: str, default: Any = None) -> Any:
78
+ """Retrieve custom data"""
79
+ return self.custom_data.get(key, default)
80
+
81
+
82
+ def add_message(self, message: Dict[str, Any]) -> None:
83
+ """Add message to context"""
84
+ self.messages.append(message)
85
+
86
+ def update_agent_context(self, agent: Any, agent_name: str) -> None:
87
+ """Update agent-related context"""
88
+ self.agent = agent
89
+ self.agent_name_resolved = agent_name
90
+
91
+
92
+ # Context management functions
93
+ def get_context() -> Optional[Context]:
94
+ """Get current context from context variable"""
95
+ try:
96
+ return CONTEXT.get()
97
+ except LookupError:
98
+ return None
99
+
100
+
101
+ def set_context(context: Context) -> None:
102
+ """Set current context in context variable"""
103
+ CONTEXT.set(context)
104
+
105
+
106
+ def create_context(
107
+ request_id: Optional[str] = None,
108
+ messages: Optional[List[Dict[str, Any]]] = None,
109
+ stream: bool = False,
110
+ request: Any = None,
111
+ agent: Any = None
112
+ ) -> Context:
113
+ """Create new context with provided data"""
114
+ context = Context(
115
+ request_id=request_id or str(uuid.uuid4()),
116
+ messages=messages or [],
117
+ stream=stream,
118
+ agent=agent,
119
+ request=request
120
+ )
121
+ return context
File without changes