Current section

Files

Jump to
snakepit priv python snakepit_bridge adapters showcase showcase_adapter.py
Raw

priv/python/snakepit_bridge/adapters/showcase/showcase_adapter.py

"""
Refactored ShowcaseAdapter that delegates to specialized handlers.
This adapter demonstrates best practices for Snakepit adapters:
1. All state is managed through SessionContext (Elixir's SessionStore)
2. Code is organized into domain-specific handlers
3. Python workers remain stateless for better scalability
"""
from typing import Dict, Any
from snakepit_bridge import SessionContext
from snakepit_bridge.base_adapter import BaseAdapter, tool
from .handlers import (
BasicOpsHandler,
SessionOpsHandler,
BinaryOpsHandler,
StreamingOpsHandler,
ConcurrentOpsHandler,
VariableOpsHandler,
MLWorkflowHandler
)
class ShowcaseAdapter(BaseAdapter):
"""Main adapter demonstrating Snakepit features through specialized handlers."""
def __init__(self):
super().__init__()
# Initialize handlers
self.handlers = {
'basic': BasicOpsHandler(),
'session': SessionOpsHandler(),
'binary': BinaryOpsHandler(),
'streaming': StreamingOpsHandler(),
'concurrent': ConcurrentOpsHandler(),
'variable': VariableOpsHandler(),
'ml': MLWorkflowHandler()
}
# Build tool registry from all handlers
self._handler_tools = {}
for handler in self.handlers.values():
self._handler_tools.update(handler.get_tools())
# Session context will be set by the framework
self.session_context = None
def set_session_context(self, session_context):
"""Set the session context for this adapter instance."""
self.session_context = session_context
# Legacy method for backward compatibility
def execute_tool(self, tool_name: str, arguments: Dict[str, Any], context) -> Any:
"""Execute a tool by name with given arguments (legacy support)."""
if tool_name in self._handler_tools:
tool = self._handler_tools[tool_name]
return tool.func(context, **arguments)
else:
# Try the new tool system
return self.call_tool(tool_name, **arguments)
# Expose key handler methods as tools using the decorator
@tool(description="Execute basic operations like echo and add")
def basic_echo(self, message: str) -> str:
"""Echo a message back."""
return self.handlers['basic'].get_tools()['echo'].func(self.session_context, message=message)
@tool(description="Add two numbers")
def basic_add(self, a: float, b: float) -> float:
"""Add two numbers together."""
return self.handlers['basic'].get_tools()['add'].func(self.session_context, a=a, b=b)
@tool(description="Perform text analysis using ML")
def ml_analyze_text(self, text: str) -> Dict[str, Any]:
"""Analyze text using machine learning."""
return self.handlers['ml'].get_tools()['analyze_text'].func(self.session_context, text=text)
@tool(description="Process binary data", supports_streaming=False)
def process_binary(self, data: bytes, operation: str = 'checksum') -> Any:
"""Process binary data with specified operation."""
return self.handlers['binary'].get_tools()['process_binary'].func(
self.session_context,
data=data,
operation=operation
)
@tool(description="Demonstrate variable operations")
def variable_demo(self, name: str, value: Any) -> Dict[str, Any]:
"""Demonstrate variable storage and retrieval."""
return self.handlers['variable'].get_tools()['variable_demo'].func(
self.session_context,
name=name,
value=value
)
@tool(description="Stream data in chunks", supports_streaming=True)
def stream_data(self, count: int = 5, delay: float = 1.0):
"""Stream data chunks with optional delay."""
handler_tool = self.handlers['streaming'].get_tools()['stream_data']
# This returns a generator for streaming
return handler_tool.func(self.session_context, count=count, delay=delay)
@tool(description="Execute concurrent tasks")
def concurrent_demo(self, task_count: int = 3) -> Dict[str, Any]:
"""Execute multiple tasks concurrently."""
return self.handlers['concurrent'].get_tools()['concurrent_demo'].func(
self.session_context,
task_count=task_count
)
@tool(description="Demonstrate integration with Elixir tools",
required_variables=["elixir_tools_enabled"])
def call_elixir_demo(self, tool_name: str, **kwargs) -> Any:
"""
Demonstrate calling an Elixir tool from Python.
This showcases the bidirectional tool bridge where Python
can seamlessly call tools implemented in Elixir.
"""
if not self.session_context:
raise RuntimeError("Session context not initialized")
# Check if Elixir tools are available
if tool_name in self.session_context.elixir_tools:
result = self.session_context.call_elixir_tool(tool_name, **kwargs)
return {
'tool': tool_name,
'result': result,
'source': 'elixir',
'message': f'Successfully called Elixir tool: {tool_name}'
}
else:
available = list(self.session_context.elixir_tools.keys())
return {
'error': f'Elixir tool {tool_name} not found',
'available_tools': available,
'hint': 'Make sure the tool is registered in Elixir with exposed_to_python: true'
}