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
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
|