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
@@ -0,0 +1,293 @@
1
+ """
2
+ Agent Handoffs - Robutler V2.0
3
+
4
+ LocalAgentHandoff implementation for same-instance agent transfers.
5
+ Provides basic agent-to-agent handoff functionality within a single server instance.
6
+ """
7
+
8
+ import asyncio
9
+ import time
10
+ from typing import Dict, Any, List, Optional, Union
11
+ from dataclasses import dataclass
12
+ from datetime import datetime
13
+
14
+ from ..skills.base import HandoffResult
15
+ from ...server.context.context_vars import get_context, create_context, set_context
16
+
17
+
18
+ @dataclass
19
+ class HandoffExecution:
20
+ """Record of handoff execution"""
21
+ timestamp: datetime
22
+ source_agent: str
23
+ target_agent: str
24
+ handoff_type: str
25
+ context_data: Dict[str, Any]
26
+ result: Any
27
+ duration_ms: float
28
+ success: bool
29
+ error: Optional[str] = None
30
+
31
+
32
+ class LocalAgentHandoff:
33
+ """
34
+ LocalAgentHandoff - Same-instance agent handoff system
35
+
36
+ Features:
37
+ - Agent-to-agent transfers within the same server instance
38
+ - Context preservation and transfer
39
+ - Handoff execution tracking and history
40
+ - Automatic context cleanup and management
41
+ """
42
+
43
+ def __init__(self, agents: Dict[str, 'BaseAgent']):
44
+ """
45
+ Initialize LocalAgentHandoff with available agents
46
+
47
+ Args:
48
+ agents: Dictionary of agent_name -> BaseAgent instances
49
+ """
50
+ self.agents = agents
51
+ self.handoff_history: List[HandoffExecution] = []
52
+ self.active_handoffs: Dict[str, str] = {} # handoff_id -> target_agent
53
+
54
+ def register_agent(self, agent_name: str, agent: 'BaseAgent') -> None:
55
+ """Register an agent for handoffs"""
56
+ self.agents[agent_name] = agent
57
+
58
+ def unregister_agent(self, agent_name: str) -> None:
59
+ """Unregister an agent"""
60
+ if agent_name in self.agents:
61
+ del self.agents[agent_name]
62
+
63
+ def get_available_agents(self) -> List[str]:
64
+ """Get list of available agents for handoff"""
65
+ return list(self.agents.keys())
66
+
67
+ async def execute_handoff(
68
+ self,
69
+ source_agent: str,
70
+ target_agent: str,
71
+ handoff_data: Dict[str, Any] = None,
72
+ preserve_context: bool = True
73
+ ) -> HandoffResult:
74
+ """
75
+ Execute handoff from source agent to target agent
76
+
77
+ Args:
78
+ source_agent: Name of the source agent
79
+ target_agent: Name of the target agent
80
+ handoff_data: Additional data to pass to target agent
81
+ preserve_context: Whether to preserve request context
82
+
83
+ Returns:
84
+ HandoffResult with execution details
85
+ """
86
+ start_time = datetime.utcnow()
87
+ handoff_id = f"handoff_{int(time.time())}_{source_agent}_to_{target_agent}"
88
+
89
+ try:
90
+ # Validate agents exist
91
+ if source_agent not in self.agents:
92
+ raise ValueError(f"Source agent '{source_agent}' not found")
93
+ if target_agent not in self.agents:
94
+ raise ValueError(f"Target agent '{target_agent}' not found")
95
+
96
+ source = self.agents[source_agent]
97
+ target = self.agents[target_agent]
98
+
99
+ # Get current context
100
+ current_context = get_context()
101
+ if not current_context:
102
+ raise ValueError("No active context for handoff")
103
+
104
+ # Prepare handoff context data
105
+ context_data = {
106
+ 'source_agent': source_agent,
107
+ 'target_agent': target_agent,
108
+ 'handoff_id': handoff_id,
109
+ 'handoff_timestamp': start_time.isoformat(),
110
+ 'handoff_data': handoff_data or {}
111
+ }
112
+
113
+ # Create new context for target agent if preserving context
114
+ if preserve_context:
115
+ target_context = create_context(
116
+ request_id=current_context.request_id,
117
+ peer_user_id=current_context.peer_user_id,
118
+ payment_user_id=current_context.payment_user_id,
119
+ origin_user_id=current_context.origin_user_id,
120
+ agent_owner_user_id=current_context.agent_owner_user_id,
121
+ messages=current_context.messages.copy(),
122
+ stream=current_context.stream
123
+ )
124
+
125
+ # Add handoff context data
126
+ target_context.set("handoff_context", context_data)
127
+ target_context.update_agent_context(target, target_agent)
128
+ set_context(target_context)
129
+
130
+ # Track active handoff
131
+ self.active_handoffs[handoff_id] = target_agent
132
+
133
+ # Execute source agent's handoff hooks (if any)
134
+ if hasattr(source, '_execute_hooks'):
135
+ current_context.set("handoff_data", context_data)
136
+ await source._execute_hooks("before_handoff", current_context)
137
+
138
+ # Create handoff message for target agent
139
+ handoff_message = {
140
+ "role": "system",
141
+ "content": f"Handoff from {source_agent}: {handoff_data.get('reason', 'Agent transfer requested')}"
142
+ }
143
+
144
+ # Add handoff context to messages
145
+ messages_with_handoff = current_context.messages + [handoff_message]
146
+ if handoff_data and handoff_data.get('user_message'):
147
+ messages_with_handoff.append({
148
+ "role": "user",
149
+ "content": handoff_data['user_message']
150
+ })
151
+
152
+ # Execute target agent with handoff context
153
+ # Note: This is a basic implementation - could be enhanced with specific handoff methods
154
+ response = await target.run(
155
+ messages=messages_with_handoff,
156
+ tools=handoff_data.get('tools', []),
157
+ stream=False
158
+ )
159
+
160
+ # Execute target agent's handoff hooks (if any)
161
+ if hasattr(target, '_execute_hooks'):
162
+ if preserve_context:
163
+ target_context.set("handoff_result", response)
164
+ await target._execute_hooks("after_handoff", target_context)
165
+
166
+ # Calculate duration
167
+ duration_ms = (datetime.utcnow() - start_time).total_seconds() * 1000
168
+
169
+ # Record successful handoff
170
+ execution = HandoffExecution(
171
+ timestamp=start_time,
172
+ source_agent=source_agent,
173
+ target_agent=target_agent,
174
+ handoff_type="local_agent",
175
+ context_data=context_data,
176
+ result=response,
177
+ duration_ms=duration_ms,
178
+ success=True
179
+ )
180
+ self.handoff_history.append(execution)
181
+
182
+ # Remove from active handoffs
183
+ if handoff_id in self.active_handoffs:
184
+ del self.active_handoffs[handoff_id]
185
+
186
+ # Return handoff result
187
+ return HandoffResult(
188
+ result=response,
189
+ handoff_type="local_agent",
190
+ success=True,
191
+ metadata={
192
+ 'handoff_id': handoff_id,
193
+ 'source_agent': source_agent,
194
+ 'target_agent': target_agent,
195
+ 'duration_ms': duration_ms,
196
+ 'context_preserved': preserve_context
197
+ }
198
+ )
199
+
200
+ except Exception as e:
201
+ # Calculate duration
202
+ duration_ms = (datetime.utcnow() - start_time).total_seconds() * 1000
203
+
204
+ # Record failed handoff
205
+ execution = HandoffExecution(
206
+ timestamp=start_time,
207
+ source_agent=source_agent,
208
+ target_agent=target_agent,
209
+ handoff_type="local_agent",
210
+ context_data=context_data if 'context_data' in locals() else {},
211
+ result=None,
212
+ duration_ms=duration_ms,
213
+ success=False,
214
+ error=str(e)
215
+ )
216
+ self.handoff_history.append(execution)
217
+
218
+ # Clean up active handoff
219
+ if handoff_id in self.active_handoffs:
220
+ del self.active_handoffs[handoff_id]
221
+
222
+ # Return error result
223
+ return HandoffResult(
224
+ result=None,
225
+ handoff_type="local_agent",
226
+ success=False,
227
+ metadata={
228
+ 'handoff_id': handoff_id if 'handoff_id' in locals() else 'unknown',
229
+ 'error': str(e),
230
+ 'duration_ms': duration_ms
231
+ }
232
+ )
233
+
234
+ def get_handoff_history(self, limit: Optional[int] = None) -> List[HandoffExecution]:
235
+ """Get handoff execution history"""
236
+ history = sorted(self.handoff_history, key=lambda x: x.timestamp, reverse=True)
237
+ if limit:
238
+ history = history[:limit]
239
+ return history
240
+
241
+ def get_active_handoffs(self) -> Dict[str, str]:
242
+ """Get currently active handoffs"""
243
+ return self.active_handoffs.copy()
244
+
245
+ def get_handoff_stats(self) -> Dict[str, Any]:
246
+ """Get handoff statistics"""
247
+ if not self.handoff_history:
248
+ return {
249
+ 'total_handoffs': 0,
250
+ 'success_rate': 0.0,
251
+ 'average_duration_ms': 0.0,
252
+ 'most_common_source': None,
253
+ 'most_common_target': None
254
+ }
255
+
256
+ successful = [h for h in self.handoff_history if h.success]
257
+ failed = [h for h in self.handoff_history if not h.success]
258
+
259
+ # Calculate statistics
260
+ total = len(self.handoff_history)
261
+ success_rate = len(successful) / total if total > 0 else 0.0
262
+ avg_duration = sum(h.duration_ms for h in successful) / len(successful) if successful else 0.0
263
+
264
+ # Most common source and target
265
+ sources = [h.source_agent for h in self.handoff_history]
266
+ targets = [h.target_agent for h in self.handoff_history]
267
+
268
+ most_common_source = max(set(sources), key=sources.count) if sources else None
269
+ most_common_target = max(set(targets), key=targets.count) if targets else None
270
+
271
+ return {
272
+ 'total_handoffs': total,
273
+ 'successful_handoffs': len(successful),
274
+ 'failed_handoffs': len(failed),
275
+ 'success_rate': success_rate,
276
+ 'average_duration_ms': avg_duration,
277
+ 'most_common_source': most_common_source,
278
+ 'most_common_target': most_common_target
279
+ }
280
+
281
+
282
+ # Factory function for easy creation
283
+ def create_local_handoff_system(agents: Dict[str, 'BaseAgent']) -> LocalAgentHandoff:
284
+ """
285
+ Factory function to create LocalAgentHandoff system
286
+
287
+ Args:
288
+ agents: Dictionary of agent_name -> BaseAgent instances
289
+
290
+ Returns:
291
+ Configured LocalAgentHandoff instance
292
+ """
293
+ return LocalAgentHandoff(agents)
File without changes
File without changes
File without changes
@@ -0,0 +1,109 @@
1
+ """
2
+ Robutler Agents Skills
3
+
4
+ This module provides the skill system for Robutler agents, including core skills,
5
+ platform skills, and ecosystem skills. Skills are modular components that provide
6
+ specific functionality to agents.
7
+ """
8
+
9
+ from .base import Skill, Handoff, HandoffResult
10
+
11
+ # Import all core skills that are always available
12
+ from .core.llm.litellm import LiteLLMSkill
13
+
14
+ # Core skills - these are fundamental and always available
15
+ CORE_SKILLS = {
16
+ "litellm": LiteLLMSkill,
17
+ }
18
+
19
+ # Import Robutler platform skills
20
+ from .robutler.crm import CRMAnalyticsSkill
21
+
22
+ # Robutler platform skills - these integrate with Robutler services
23
+ ROBUTLER_SKILLS = {
24
+ "crm": CRMAnalyticsSkill,
25
+ "analytics": CRMAnalyticsSkill, # Alias for convenience
26
+ }
27
+
28
+ # Ecosystem skills - these integrate with external services
29
+ ECOSYSTEM_SKILLS = {
30
+ # Will be populated as ecosystem integrations are implemented
31
+ }
32
+
33
+ # Combined skills registry
34
+ ALL_SKILLS = {
35
+ **CORE_SKILLS,
36
+ **ROBUTLER_SKILLS,
37
+ **ECOSYSTEM_SKILLS
38
+ }
39
+
40
+ # Export main classes and registries
41
+ __all__ = [
42
+ # Base classes
43
+ 'Skill',
44
+ 'Handoff',
45
+ 'HandoffResult',
46
+
47
+ # Skill registries
48
+ 'CORE_SKILLS',
49
+ 'ROBUTLER_SKILLS',
50
+ 'ECOSYSTEM_SKILLS',
51
+ 'ALL_SKILLS',
52
+
53
+ # Core skills
54
+ 'LiteLLMSkill',
55
+ ]
56
+
57
+ # Lazy loading for ecosystem skills to avoid heavy imports
58
+ def get_skill(skill_name: str):
59
+ """Get a skill class by name, with lazy loading for ecosystem skills
60
+
61
+ Args:
62
+ skill_name: Name of the skill to load
63
+
64
+ Returns:
65
+ Skill class if found, None otherwise
66
+ """
67
+ # Check core skills first
68
+ if skill_name in CORE_SKILLS:
69
+ return CORE_SKILLS[skill_name]
70
+
71
+ # Check platform skills
72
+ if skill_name in ROBUTLER_SKILLS:
73
+ return ROBUTLER_SKILLS[skill_name]
74
+
75
+ # Lazy load ecosystem skills
76
+ ecosystem_imports = {
77
+ "google": ("robutler.agents.skills.ecosystem.google", "GoogleSkill"),
78
+ "database": ("robutler.agents.skills.ecosystem.database", "DatabaseSkill"),
79
+ "filesystem": ("robutler.agents.skills.ecosystem.filesystem", "FilesystemSkill"),
80
+ "web": ("robutler.agents.skills.ecosystem.web", "WebSkill"),
81
+ "crewai": ("robutler.agents.skills.ecosystem.crewai", "CrewAISkill"),
82
+ "n8n": ("robutler.agents.skills.ecosystem.n8n", "N8nSkill"),
83
+ "zapier": ("robutler.agents.skills.ecosystem.zapier", "ZapierSkill"),
84
+ }
85
+
86
+ if skill_name in ecosystem_imports:
87
+ try:
88
+ module_path, class_name = ecosystem_imports[skill_name]
89
+ module = __import__(module_path, fromlist=[class_name])
90
+ skill_class = getattr(module, class_name)
91
+ ECOSYSTEM_SKILLS[skill_name] = skill_class
92
+ return skill_class
93
+ except ImportError:
94
+ # Ecosystem skill not available
95
+ return None
96
+
97
+ return None
98
+
99
+ def list_available_skills() -> dict:
100
+ """List all available skills by category
101
+
102
+ Returns:
103
+ Dict with skill categories and their available skills
104
+ """
105
+ return {
106
+ "core": list(CORE_SKILLS.keys()),
107
+ "webagents": list(ROBUTLER_SKILLS.keys()),
108
+ "ecosystem": list(ECOSYSTEM_SKILLS.keys())
109
+ }
@@ -0,0 +1,136 @@
1
+ """
2
+ Base Skill Interface - Robutler V2.0
3
+
4
+ Core skill interface with unified context access, automatic registration support,
5
+ and dependency resolution.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+ from typing import Dict, Any, List, Optional, Callable, Union, TYPE_CHECKING
10
+ from dataclasses import dataclass
11
+
12
+ if TYPE_CHECKING:
13
+ from ..core.base_agent import BaseAgent
14
+
15
+
16
+ class Skill(ABC):
17
+ """Base interface for agent skills with unified context access
18
+
19
+ Skills have access to everything through a single Context object:
20
+ - During initialization: Basic agent reference for registration
21
+ - During request processing: Full Context via get_context()
22
+
23
+ The Context contains BOTH request data AND agent capabilities:
24
+ - Request: messages, user, streaming, usage, etc.
25
+ - Agent: skills, tools, hooks, capabilities, etc.
26
+ """
27
+
28
+ def __init__(self, config: Dict[str, Any] = None, scope: str = "all", dependencies: List[str] = None):
29
+ self.config = config or {}
30
+ self.scope = scope # "all", "owner", "admin" - controls skill availability
31
+ self.dependencies = dependencies or [] # List of skill names this skill depends on
32
+ self.skill_name = self.__class__.__name__ # For tracking registration source
33
+ self.agent = None # BaseAgent reference - set during initialization
34
+
35
+ async def initialize(self, agent: 'BaseAgent') -> None:
36
+ """
37
+ Initialize skill with agent reference.
38
+ Skills should register their tools, hooks, and handoffs here.
39
+
40
+ Args:
41
+ agent: The BaseAgent instance (for registration only)
42
+ """
43
+ self.agent = agent
44
+ # Subclasses implement their registration logic here
45
+
46
+ def get_tools(self) -> List[Callable]:
47
+ """Return tools that this skill provides (from agent's central registry)"""
48
+ if not self.agent:
49
+ return []
50
+ return [tool['function'] for tool in self.agent.get_all_tools()
51
+ if tool.get('source') == self.skill_name]
52
+
53
+ def register_tool(self, tool_func: Callable, scope: str = None) -> None:
54
+ """Register a tool with the agent (central registration)
55
+
56
+ Can be called during initialization or at runtime from hooks/tools.
57
+ """
58
+ if not self.agent:
59
+ raise RuntimeError("Cannot register tool: skill not initialized")
60
+
61
+ # Use provided scope or fall back to skill's default scope
62
+ effective_scope = scope if scope is not None else self.scope
63
+
64
+ # Allow skill to override tool scope if provided
65
+ if scope and hasattr(tool_func, '_tool_scope'):
66
+ tool_func._tool_scope = scope
67
+
68
+ # Register with agent's central registry
69
+ self.agent.register_tool(tool_func, source=self.skill_name, scope=effective_scope)
70
+
71
+ def register_hook(self, event: str, handler: Callable, priority: int = 50) -> None:
72
+ """Register a hook for lifecycle events (central registration)
73
+
74
+ Hooks receive and return the unified Context object containing everything.
75
+ """
76
+ if not self.agent:
77
+ raise RuntimeError("Cannot register hook: skill not initialized")
78
+
79
+ # Register with agent's central registry
80
+ self.agent.register_hook(event, handler, priority, source=self.skill_name)
81
+
82
+ def register_handoff(self, handoff_config: 'Handoff') -> None:
83
+ """Register a handoff configuration"""
84
+ if not self.agent:
85
+ raise RuntimeError("Cannot register handoff: skill not initialized")
86
+
87
+ # Register with agent's central registry
88
+ self.agent.register_handoff(handoff_config, source=self.skill_name)
89
+
90
+ # Everything accessible via unified Context during request processing
91
+ def get_context(self) -> Optional['Context']:
92
+ """
93
+ Get unified Context containing EVERYTHING:
94
+
95
+ Request data:
96
+ - context.messages, context.user, context.stream
97
+ - context.track_usage(), context.get()/set()
98
+
99
+ Agent capabilities:
100
+ - context.agent_skills, context.agent_tools, context.agent_handoffs
101
+ - context.agent (BaseAgent instance)
102
+ """
103
+ from ...server.context.context_vars import get_context
104
+ return get_context()
105
+
106
+ def get_dependencies(self) -> List[str]:
107
+ """Return list of skill dependencies"""
108
+ return self.dependencies.copy()
109
+
110
+
111
+ # Base dataclasses for handoffs and other components
112
+ @dataclass
113
+ class Handoff:
114
+ """Configuration for handoff operations"""
115
+ target: str
116
+ handoff_type: str
117
+ description: str = ""
118
+ scope: Union[str, List[str]] = "all"
119
+ metadata: Dict[str, Any] = None
120
+
121
+ def __post_init__(self):
122
+ if self.metadata is None:
123
+ self.metadata = {}
124
+
125
+
126
+ @dataclass
127
+ class HandoffResult:
128
+ """Result from handoff execution"""
129
+ result: Any
130
+ handoff_type: str
131
+ metadata: Dict[str, Any] = None
132
+ success: bool = True
133
+
134
+ def __post_init__(self):
135
+ if self.metadata is None:
136
+ self.metadata = {}
@@ -0,0 +1,8 @@
1
+ """
2
+ Core Skills Package - Essential agent capabilities
3
+ """
4
+
5
+ from .planning import PlannerSkill
6
+ from .memory import ShortTermMemorySkill, LongTermMemorySkill, MemoryItem
7
+
8
+ __all__ = ['PlannerSkill', 'ShortTermMemorySkill', 'LongTermMemorySkill', 'MemoryItem']
File without changes
File without changes
@@ -0,0 +1 @@
1
+ # TODO: Implement dedicated Anthropic skill, currently using litellm
@@ -0,0 +1,10 @@
1
+ """
2
+ LiteLLM Skill Package - Robutler V2.0
3
+
4
+ Cross-provider LLM routing with support for OpenAI, Anthropic, XAI/Grok, and more.
5
+ Provides unified interface for multiple LLM providers with automatic fallbacks.
6
+ """
7
+
8
+ from .skill import LiteLLMSkill
9
+
10
+ __all__ = ["LiteLLMSkill"]