-
Notifications
You must be signed in to change notification settings - Fork 704
Expand file tree
/
Copy pathbase.py
More file actions
161 lines (124 loc) · 5.04 KB
/
base.py
File metadata and controls
161 lines (124 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""Base class for token-related skills."""
import logging
from typing import Any, Dict, Optional
import aiohttp
from langchain_core.runnables import RunnableConfig
from abstracts.skill import SkillStoreABC
from skills.base import IntentKitSkill, SkillContext
from skills.token.constants import MORALIS_API_BASE_URL
logger = logging.getLogger(__name__)
class TokenBaseTool(IntentKitSkill):
"""Base class for all token-related skills.
This base class provides common functionality for token API interactions,
including making HTTP requests to the Moralis API.
"""
def __init__(self, skill_store: SkillStoreABC = None):
"""Initialize the token tool with a skill store."""
super().__init__(skill_store=skill_store)
@property
def category(self) -> str:
return "token"
def get_api_key(self, context: SkillContext) -> str:
"""Get API key from agent config or system config.
Args:
context: The skill context containing the agent config
Returns:
The API key to use for API requests
Raises:
ValueError: If no API key is available
"""
skill_config = context.config
if skill_config.get("api_key_provider") == "agent_owner":
api_key = skill_config.get("api_key")
if not api_key:
raise ValueError(
"No agent-specific API key provided in the configuration."
)
return api_key
api_key = self.skill_store.get_system_config("moralis_api_key")
if not api_key:
raise ValueError("No Moralis API key provided in the configuration.")
return api_key
def context_from_config(self, config: Optional[RunnableConfig] = None) -> Any:
"""Extract context from the runnable config.
Raises:
ValueError: If config is invalid or missing required fields
"""
if not config:
raise ValueError("No config provided to context_from_config")
if "configurable" not in config:
raise ValueError("'configurable' not in config")
if "agent" not in config["configurable"]:
raise ValueError("'agent' not in config['configurable']")
agent = config["configurable"].get("agent")
category_config = None
if agent.skills:
category_config = agent.skills.get(self.category)
if not category_config:
category_config = getattr(agent, self.category + "_config", {})
if not category_config:
category_config = {}
from skills.base import SkillContext
context = SkillContext(
agent=agent,
config=category_config,
user_id=config["configurable"].get("user_id"),
entrypoint=config["configurable"].get("entrypoint"),
)
return context
def _prepare_params(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""Convert boolean values to lowercase strings for API compatibility.
Args:
params: Dictionary with query parameters that may contain boolean values
Returns:
Dictionary with boolean values converted to lowercase strings
"""
if not params:
return params
result = {}
for key, value in params.items():
if isinstance(value, bool):
result[key] = str(value).lower()
else:
result[key] = value
return result
async def _make_request(
self,
method: str,
endpoint: str,
api_key: str,
params: Dict[str, Any] = None,
data: Dict[str, Any] = None,
) -> Dict[str, Any]:
"""Make a request to the Moralis API.
Args:
method: HTTP method (GET, POST, etc.)
endpoint: API endpoint (without base URL)
api_key: Moralis API key
params: Query parameters
data: Request body data for POST requests
Returns:
Response data as dictionary
Raises:
ValueError: If API key is missing
aiohttp.ClientError: For HTTP client errors
Exception: For API errors or unexpected errors
"""
url = f"{MORALIS_API_BASE_URL}{endpoint}"
if not api_key:
raise ValueError("API key is missing")
headers = {"accept": "application/json", "X-API-Key": api_key}
processed_params = self._prepare_params(params) if params else None
async with aiohttp.ClientSession() as session:
async with session.request(
method=method,
url=url,
headers=headers,
params=processed_params,
json=data,
) as response:
if response.status >= 400:
error_text = await response.text()
logger.error(f"API error {response.status}: {error_text}")
raise Exception(f"API error {response.status}: {error_text}")
return await response.json()