"""
Pattern 97: Adapter Pattern
Adapt incompatible interfaces between agents or systems, allowing them to work together.
Translates data formats, protocols, and communication patterns.
"""
from typing import Dict, Any, List, Optional, Protocol
from dataclasses import dataclass, field
from datetime import datetime
from abc import ABC, abstractmethod
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
import json
class AgentInterface(ABC):
"""Standard agent interface."""
@abstractmethod
def process(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""Process data in standard format."""
pass
class LegacySystemA:
"""Legacy system with incompatible interface."""
def execute_command(self, cmd: str, params: List[str]) -> str:
"""Legacy method with string-based interface."""
return f"LegacyA executed: {cmd} with {params}"
class LegacySystemB:
"""Another legacy system with different interface."""
def run_task(self, task_id: int, config: str) -> tuple:
"""Legacy method returning tuple."""
return (task_id, f"Task {task_id} completed", config)
@dataclass
class AdaptedRequest:
"""Standardized request format."""
action: str
parameters: Dict[str, Any]
timestamp: datetime = field(default_factory=datetime.now)
@dataclass
class AdaptedResponse:
"""Standardized response format."""
success: bool
data: Any
message: str
timestamp: datetime = field(default_factory=datetime.now)
class LegacySystemAAdapter(AgentInterface):
"""Adapter for LegacySystemA."""
def __init__(self):
self.system = LegacySystemA()
def process(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""Adapt standard format to LegacySystemA format."""
# Convert standard format to legacy format
cmd = data.get("action", "default")
params = data.get("parameters", {})
params_list = [f"{k}={v}" for k, v in params.items()]
# Call legacy method
result = self.system.execute_command(cmd, params_list)
# Convert result back to standard format
return {
"success": True,
"data": result,
"message": "LegacySystemA adapted successfully"
}
class LegacySystemBAdapter(AgentInterface):
"""Adapter for LegacySystemB."""
def __init__(self):
self.system = LegacySystemB()
def process(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""Adapt standard format to LegacySystemB format."""
# Convert standard format to legacy format
task_id = hash(data.get("action", "")) % 10000
config = json.dumps(data.get("parameters", {}))
# Call legacy method
result_tuple = self.system.run_task(task_id, config)
# Convert tuple result back to standard format
return {
"success": True,
"data": {
"task_id": result_tuple[0],
"message": result_tuple[1],
"config": result_tuple[2]
},
"message": "LegacySystemB adapted successfully"
}
class ModernAgent(AgentInterface):
"""Modern agent with standard interface."""
def __init__(self, name: str, model_name: str = "gpt-4"):
self.name = name
self.llm = ChatOpenAI(model=model_name, temperature=0.5)
def process(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""Process with LLM."""
prompt = ChatPromptTemplate.from_messages([
("system", f"You are {self.name}. Process the request and provide a response."),
("human", "Action: {action}\nParameters: {parameters}")
])
chain = prompt | self.llm
response = chain.invoke({
"action": data.get("action", ""),
"parameters": str(data.get("parameters", {}))
})
return {
"success": True,
"data": response.content,
"message": f"Processed by {self.name}"
}
class AdapterPattern:
"""
Adapter Pattern - Manage adapters for different systems.
"""
def __init__(self, model_name: str = "gpt-4"):
self.model_name = model_name
self.adapters: Dict[str, AgentInterface] = {}
self.call_history: List[Dict[str, Any]] = []
def register_adapter(self, name: str, adapter: AgentInterface):
"""Register an adapter."""
self.adapters[name] = adapter
print(f"Adapter registered: {name}")
def process_request(self, adapter_name: str, request: AdaptedRequest) -> AdaptedResponse:
"""Process request through specified adapter."""
if adapter_name not in self.adapters:
return AdaptedResponse(
success=False,
data=None,
message=f"Adapter {adapter_name} not found"
)
adapter = self.adapters[adapter_name]
# Convert request to dict
request_data = {
"action": request.action,
"parameters": request.parameters
}
# Process through adapter
result = adapter.process(request_data)
# Track call
self.call_history.append({
"adapter": adapter_name,
"request": request_data,
"response": result,
"timestamp": datetime.now()
})
# Convert to standard response
return AdaptedResponse(
success=result.get("success", False),
data=result.get("data"),
message=result.get("message", "")
)
def run(self, adapter_name: str, action: str,
parameters: Dict[str, Any]) -> Dict[str, Any]:
"""Execute through adapter."""
request = AdaptedRequest(action=action, parameters=parameters)
response = self.process_request(adapter_name, request)
return {
"adapter": adapter_name,
"request": {
"action": action,
"parameters": parameters
},
"response": {
"success": response.success,
"data": response.data,
"message": response.message
}
}
def get_statistics(self) -> Dict[str, Any]:
"""Get adapter usage statistics."""
return {
"total_adapters": len(self.adapters),
"total_calls": len(self.call_history),
"calls_by_adapter": {
name: sum(1 for call in self.call_history if call["adapter"] == name)
for name in self.adapters.keys()
}
}
# Example usage
if __name__ == "__main__":
# Create pattern
pattern = AdapterPattern()
# Register adapters
pattern.register_adapter("legacy_a", LegacySystemAAdapter())
pattern.register_adapter("legacy_b", LegacySystemBAdapter())
pattern.register_adapter("modern", ModernAgent("ModernProcessor"))
print("\n=== Adapter Pattern Demo ===\n")
# Test LegacySystemA adapter
print("1. Testing LegacySystemA Adapter:")
result1 = pattern.run(
"legacy_a",
action="deploy",
parameters={"env": "production", "version": "2.0"}
)
print(f" Action: {result1['request']['action']}")
print(f" Response: {result1['response']['data']}")
print(f" Message: {result1['response']['message']}\n")
# Test LegacySystemB adapter
print("2. Testing LegacySystemB Adapter:")
result2 = pattern.run(
"legacy_b",
action="backup",
parameters={"database": "users", "incremental": True}
)
print(f" Action: {result2['request']['action']}")
print(f" Response Data: {result2['response']['data']}")
print(f" Message: {result2['response']['message']}\n")
# Test Modern agent
print("3. Testing Modern Agent:")
result3 = pattern.run(
"modern",
action="analyze",
parameters={"dataset": "sales_q4", "metric": "revenue"}
)
print(f" Action: {result3['request']['action']}")
print(f" Response: {result3['response']['data'][:100]}...")
print(f" Message: {result3['response']['message']}\n")
# Show statistics
print("=== Statistics ===")
stats = pattern.get_statistics()
print(f"Total adapters: {stats['total_adapters']}")
print(f"Total calls: {stats['total_calls']}")
print(f"Calls by adapter: {stats['calls_by_adapter']}")
Agentic Architecture Pattern: Adapter
Pattern 97: 97 Adapter – Line-by-Line Explanation
Overview
Pattern 97: Adapter Pattern
Adapt incompatible interfaces between agents or systems, allowing them to work together. Translates data formats, protocols, and communication patterns.
Code Structure Analysis
File Information
- Pattern Number: 97
- Pattern Name: 97 Adapter
- File Path:
patterns\tool_resource\97_adapter.py - Total Lines: 269
Detailed Code Explanation
Module Docstring
"""
Pattern 97: Adapter Pattern
Adapt incompatible interfaces between agents or systems, allowing them to work together.
Translates data formats, protocols, and communication patterns.
"""
Explanation: This module docstring describes the purpose and key features of the 97 Adapter pattern.
Imports Section
from typing import Dict, Any, List, Optional, Protocol
from dataclasses import dataclass, field
from datetime import datetime
from abc import ABC, abstractmethod
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
import json # First 20 imports shown
Explanation: The module imports necessary dependencies:
– from typing import Dict, Any, List, Optional, Protocol: Type hints for better code documentation
– from dataclasses import dataclass, field: Data class decorators for clean data structures
– from datetime import datetime: Date and time utilities
– from langchain_core.prompts import ChatPromptTemplate: LangChain framework integration
– from langchain_openai import ChatOpenAI: LangChain framework integration
– import json: JSON parsing and serialization
Classes
AgentInterface (Line 17)
Description: Standard agent interface.
Methods:
process (Line 21)
def process(self, data):
"""Process data in standard format."""
Purpose: Process data in standard format.
Parameters:
– self: Instance reference
– data: Input data to process
LegacySystemA (Line 26)
Description: Legacy system with incompatible interface.
Methods:
execute_command (Line 29)
def execute_command(self, cmd, params):
"""Legacy method with string-based interface."""
Purpose: Legacy method with string-based interface.
Parameters:
– self: Instance reference
– cmd: Parameter for cmd
– params: Parameter for params
LegacySystemB (Line 34)
Description: Another legacy system with different interface.
Methods:
run_task (Line 37)
def run_task(self, task_id, config):
"""Legacy method returning tuple."""
Purpose: Legacy method returning tuple.
Parameters:
– self: Instance reference
– task_id: Parameter for task_id
– config: Configuration settings
AdaptedRequest (Line 43)
Description: Standardized request format.
AdaptedResponse (Line 51)
Description: Standardized response format.
LegacySystemAAdapter (Line 59)
Description: Adapter for LegacySystemA.
Methods:
__init__ (Line 62)
def __init__(self):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
process (Line 65)
def process(self, data):
"""Adapt standard format to LegacySystemA format."""
Purpose: Adapt standard format to LegacySystemA format.
Parameters:
– self: Instance reference
– data: Input data to process
LegacySystemBAdapter (Line 83)
Description: Adapter for LegacySystemB.
Methods:
__init__ (Line 86)
def __init__(self):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
process (Line 89)
def process(self, data):
"""Adapt standard format to LegacySystemB format."""
Purpose: Adapt standard format to LegacySystemB format.
Parameters:
– self: Instance reference
– data: Input data to process
ModernAgent (Line 110)
Description: Modern agent with standard interface.
Methods:
__init__ (Line 113)
def __init__(self, name, model_name):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
– name: Identifier or label
– model_name: LLM model to use (e.g., “gpt-4”)
process (Line 117)
def process(self, data):
"""Process with LLM."""
Purpose: Process with LLM.
Parameters:
– self: Instance reference
– data: Input data to process
AdapterPattern (Line 137)
Description: Adapter Pattern – Manage adapters for different systems.
Methods:
__init__ (Line 142)
def __init__(self, model_name):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
– model_name: LLM model to use (e.g., “gpt-4”)
register_adapter (Line 147)
def register_adapter(self, name, adapter):
"""Register an adapter."""
Purpose: Register an adapter.
Parameters:
– self: Instance reference
– name: Identifier or label
– adapter: Parameter for adapter
process_request (Line 152)
def process_request(self, adapter_name, request):
"""Process request through specified adapter."""
Purpose: Process request through specified adapter.
Parameters:
– self: Instance reference
– adapter_name: Parameter for adapter_name
– request: Parameter for request
run (Line 187)
def run(self, adapter_name, action, parameters):
"""Execute through adapter."""
Purpose: Execute through adapter.
Parameters:
– self: Instance reference
– adapter_name: Parameter for adapter_name
– action: Parameter for action
– parameters: Parameter for parameters
get_statistics (Line 206)
def get_statistics(self):
"""Get adapter usage statistics."""
Purpose: Get adapter usage statistics.
Parameters:
– self: Instance reference
Design Patterns Used
- Strategy Pattern: Different execution strategies for various scenarios
- State Pattern: Managing different states in the workflow
- Chain of Responsibility: Sequential processing through workflow nodes
- Observer Pattern: Tracking and monitoring pattern execution
- Factory Pattern: Creating instances with proper configuration
Usage Example
# Initialize the pattern
pattern = AgentInterface(name="example", model_name="gpt-4")
# Configure and execute
result = pattern.execute(data={"key": "value"})
# Check results
print(result)
Key Concepts
- LLM Integration: Uses LangChain/OpenAI for intelligent decision-making
- Workflow Orchestration: LangGraph manages execution flow through nodes
- State Management: TypedDict defines workflow state structure
- Error Handling: Comprehensive error handling and fallback mechanisms
- Extensibility: Designed for easy customization and extension
Extension Points
This pattern can be extended by: 1. Adding custom workflow nodes 2. Implementing additional validation logic 3. Integrating with external services 4. Customizing LLM prompts and responses 5. Adding monitoring and logging capabilities
Leave a Reply