intentkit 0.8.11__py3-none-any.whl → 0.8.12rc0__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.
Potentially problematic release.
This version of intentkit might be problematic. Click here for more details.
- intentkit/__init__.py +1 -1
- intentkit/abstracts/graph.py +4 -0
- intentkit/abstracts/skill.py +0 -81
- intentkit/core/agent.py +0 -95
- intentkit/core/engine.py +12 -5
- intentkit/models/skill.py +38 -40
- intentkit/skills/base.py +67 -0
- intentkit/skills/casino/deck_draw.py +3 -4
- intentkit/skills/casino/deck_shuffle.py +4 -2
- intentkit/skills/cryptocompare/base.py +4 -13
- intentkit/skills/cryptocompare/fetch_news.py +1 -1
- intentkit/skills/cryptocompare/fetch_price.py +1 -1
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +1 -1
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +1 -1
- intentkit/skills/cryptocompare/fetch_top_volume.py +1 -1
- intentkit/skills/cryptocompare/fetch_trading_signals.py +1 -1
- intentkit/skills/defillama/base.py +3 -9
- intentkit/skills/enso/networks.py +1 -6
- intentkit/skills/enso/route.py +3 -5
- intentkit/skills/enso/tokens.py +2 -12
- intentkit/skills/firecrawl/clear.py +3 -6
- intentkit/skills/firecrawl/scrape.py +2 -4
- intentkit/skills/firecrawl/utils.py +14 -5
- intentkit/skills/twitter/base.py +4 -13
- intentkit/skills/twitter/follow_user.py +1 -3
- intentkit/skills/twitter/get_mentions.py +2 -7
- intentkit/skills/twitter/get_timeline.py +3 -9
- intentkit/skills/twitter/get_user_by_username.py +1 -3
- intentkit/skills/twitter/get_user_tweets.py +3 -9
- intentkit/skills/twitter/like_tweet.py +1 -3
- intentkit/skills/twitter/post_tweet.py +1 -3
- intentkit/skills/twitter/reply_tweet.py +1 -3
- intentkit/skills/twitter/retweet.py +1 -3
- intentkit/skills/twitter/search_tweets.py +3 -9
- intentkit/skills/web_scraper/scrape_and_index.py +2 -4
- intentkit/skills/web_scraper/utils.py +7 -11
- {intentkit-0.8.11.dist-info → intentkit-0.8.12rc0.dist-info}/METADATA +1 -1
- {intentkit-0.8.11.dist-info → intentkit-0.8.12rc0.dist-info}/RECORD +40 -40
- {intentkit-0.8.11.dist-info → intentkit-0.8.12rc0.dist-info}/WHEEL +0 -0
- {intentkit-0.8.11.dist-info → intentkit-0.8.12rc0.dist-info}/licenses/LICENSE +0 -0
intentkit/__init__.py
CHANGED
intentkit/abstracts/graph.py
CHANGED
intentkit/abstracts/skill.py
CHANGED
|
@@ -59,87 +59,6 @@ class SkillStoreABC(ABC):
|
|
|
59
59
|
"""
|
|
60
60
|
pass
|
|
61
61
|
|
|
62
|
-
@staticmethod
|
|
63
|
-
@abstractmethod
|
|
64
|
-
async def get_agent_skill_data(
|
|
65
|
-
agent_id: str, skill: str, key: str
|
|
66
|
-
) -> Optional[Dict[str, Any]]:
|
|
67
|
-
"""Get skill data for an agent.
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
agent_id: ID of the agent
|
|
71
|
-
skill: Name of the skill
|
|
72
|
-
key: Data key
|
|
73
|
-
|
|
74
|
-
Returns:
|
|
75
|
-
Dictionary containing the skill data if found, None otherwise
|
|
76
|
-
"""
|
|
77
|
-
pass
|
|
78
|
-
|
|
79
|
-
@staticmethod
|
|
80
|
-
@abstractmethod
|
|
81
|
-
async def save_agent_skill_data(
|
|
82
|
-
agent_id: str, skill: str, key: str, data: Dict[str, Any]
|
|
83
|
-
) -> None:
|
|
84
|
-
"""Save or update skill data for an agent.
|
|
85
|
-
|
|
86
|
-
Args:
|
|
87
|
-
agent_id: ID of the agent
|
|
88
|
-
skill: Name of the skill
|
|
89
|
-
key: Data key
|
|
90
|
-
data: JSON data to store
|
|
91
|
-
"""
|
|
92
|
-
pass
|
|
93
|
-
|
|
94
|
-
@staticmethod
|
|
95
|
-
@abstractmethod
|
|
96
|
-
async def delete_agent_skill_data(agent_id: str, skill: str, key: str) -> None:
|
|
97
|
-
"""Delete skill data for an agent.
|
|
98
|
-
|
|
99
|
-
Args:
|
|
100
|
-
agent_id: ID of the agent
|
|
101
|
-
skill: Name of the skill
|
|
102
|
-
key: Data key
|
|
103
|
-
"""
|
|
104
|
-
pass
|
|
105
|
-
|
|
106
|
-
@staticmethod
|
|
107
|
-
@abstractmethod
|
|
108
|
-
async def get_thread_skill_data(
|
|
109
|
-
thread_id: str, skill: str, key: str
|
|
110
|
-
) -> Optional[Dict[str, Any]]:
|
|
111
|
-
"""Get skill data for a thread.
|
|
112
|
-
|
|
113
|
-
Args:
|
|
114
|
-
thread_id: ID of the thread
|
|
115
|
-
skill: Name of the skill
|
|
116
|
-
key: Data key
|
|
117
|
-
|
|
118
|
-
Returns:
|
|
119
|
-
Dictionary containing the skill data if found, None otherwise
|
|
120
|
-
"""
|
|
121
|
-
pass
|
|
122
|
-
|
|
123
|
-
@staticmethod
|
|
124
|
-
@abstractmethod
|
|
125
|
-
async def save_thread_skill_data(
|
|
126
|
-
thread_id: str,
|
|
127
|
-
agent_id: str,
|
|
128
|
-
skill: str,
|
|
129
|
-
key: str,
|
|
130
|
-
data: Dict[str, Any],
|
|
131
|
-
) -> None:
|
|
132
|
-
"""Save or update skill data for a thread.
|
|
133
|
-
|
|
134
|
-
Args:
|
|
135
|
-
thread_id: ID of the thread
|
|
136
|
-
agent_id: ID of the agent that owns this thread
|
|
137
|
-
skill: Name of the skill
|
|
138
|
-
key: Data key
|
|
139
|
-
data: JSON data to store
|
|
140
|
-
"""
|
|
141
|
-
pass
|
|
142
|
-
|
|
143
62
|
@staticmethod
|
|
144
63
|
@abstractmethod
|
|
145
64
|
async def list_autonomous_tasks(agent_id: str) -> List[AgentAutonomous]:
|
intentkit/core/agent.py
CHANGED
|
@@ -25,12 +25,6 @@ from intentkit.models.credit import (
|
|
|
25
25
|
UpstreamType,
|
|
26
26
|
)
|
|
27
27
|
from intentkit.models.db import get_session
|
|
28
|
-
from intentkit.models.skill import (
|
|
29
|
-
AgentSkillData,
|
|
30
|
-
AgentSkillDataCreate,
|
|
31
|
-
ThreadSkillData,
|
|
32
|
-
ThreadSkillDataCreate,
|
|
33
|
-
)
|
|
34
28
|
from intentkit.utils.error import IntentKitAPIError
|
|
35
29
|
from intentkit.utils.slack_alert import send_slack_message
|
|
36
30
|
|
|
@@ -522,95 +516,6 @@ class AgentStore(SkillStoreABC):
|
|
|
522
516
|
async def get_agent_quota(agent_id: str) -> AgentQuota:
|
|
523
517
|
return await AgentQuota.get(agent_id)
|
|
524
518
|
|
|
525
|
-
@staticmethod
|
|
526
|
-
async def get_agent_skill_data(
|
|
527
|
-
agent_id: str, skill: str, key: str
|
|
528
|
-
) -> Optional[Dict[str, Any]]:
|
|
529
|
-
"""Get skill data for an agent.
|
|
530
|
-
|
|
531
|
-
Args:
|
|
532
|
-
agent_id: ID of the agent
|
|
533
|
-
skill: Name of the skill
|
|
534
|
-
key: Data key
|
|
535
|
-
|
|
536
|
-
Returns:
|
|
537
|
-
Dictionary containing the skill data if found, None otherwise
|
|
538
|
-
"""
|
|
539
|
-
return await AgentSkillData.get(agent_id, skill, key)
|
|
540
|
-
|
|
541
|
-
@staticmethod
|
|
542
|
-
async def save_agent_skill_data(
|
|
543
|
-
agent_id: str, skill: str, key: str, data: Dict[str, Any]
|
|
544
|
-
) -> None:
|
|
545
|
-
"""Save or update skill data for an agent.
|
|
546
|
-
|
|
547
|
-
Args:
|
|
548
|
-
agent_id: ID of the agent
|
|
549
|
-
skill: Name of the skill
|
|
550
|
-
key: Data key
|
|
551
|
-
data: JSON data to store
|
|
552
|
-
"""
|
|
553
|
-
skill_data = AgentSkillDataCreate(
|
|
554
|
-
agent_id=agent_id,
|
|
555
|
-
skill=skill,
|
|
556
|
-
key=key,
|
|
557
|
-
data=data,
|
|
558
|
-
)
|
|
559
|
-
await skill_data.save()
|
|
560
|
-
|
|
561
|
-
@staticmethod
|
|
562
|
-
async def delete_agent_skill_data(agent_id: str, skill: str, key: str) -> None:
|
|
563
|
-
"""Delete skill data for an agent.
|
|
564
|
-
|
|
565
|
-
Args:
|
|
566
|
-
agent_id: ID of the agent
|
|
567
|
-
skill: Name of the skill
|
|
568
|
-
key: Data key
|
|
569
|
-
"""
|
|
570
|
-
await AgentSkillData.delete(agent_id, skill, key)
|
|
571
|
-
|
|
572
|
-
@staticmethod
|
|
573
|
-
async def get_thread_skill_data(
|
|
574
|
-
thread_id: str, skill: str, key: str
|
|
575
|
-
) -> Optional[Dict[str, Any]]:
|
|
576
|
-
"""Get skill data for a thread.
|
|
577
|
-
|
|
578
|
-
Args:
|
|
579
|
-
thread_id: ID of the thread
|
|
580
|
-
skill: Name of the skill
|
|
581
|
-
key: Data key
|
|
582
|
-
|
|
583
|
-
Returns:
|
|
584
|
-
Dictionary containing the skill data if found, None otherwise
|
|
585
|
-
"""
|
|
586
|
-
return await ThreadSkillData.get(thread_id, skill, key)
|
|
587
|
-
|
|
588
|
-
@staticmethod
|
|
589
|
-
async def save_thread_skill_data(
|
|
590
|
-
thread_id: str,
|
|
591
|
-
agent_id: str,
|
|
592
|
-
skill: str,
|
|
593
|
-
key: str,
|
|
594
|
-
data: Dict[str, Any],
|
|
595
|
-
) -> None:
|
|
596
|
-
"""Save or update skill data for a thread.
|
|
597
|
-
|
|
598
|
-
Args:
|
|
599
|
-
thread_id: ID of the thread
|
|
600
|
-
agent_id: ID of the agent that owns this thread
|
|
601
|
-
skill: Name of the skill
|
|
602
|
-
key: Data key
|
|
603
|
-
data: JSON data to store
|
|
604
|
-
"""
|
|
605
|
-
skill_data = ThreadSkillDataCreate(
|
|
606
|
-
thread_id=thread_id,
|
|
607
|
-
agent_id=agent_id,
|
|
608
|
-
skill=skill,
|
|
609
|
-
key=key,
|
|
610
|
-
data=data,
|
|
611
|
-
)
|
|
612
|
-
await skill_data.save()
|
|
613
|
-
|
|
614
519
|
@staticmethod
|
|
615
520
|
async def list_autonomous_tasks(agent_id: str) -> List[AgentAutonomous]:
|
|
616
521
|
"""List all autonomous tasks for an agent.
|
intentkit/core/engine.py
CHANGED
|
@@ -21,6 +21,7 @@ from typing import Optional, Tuple
|
|
|
21
21
|
|
|
22
22
|
import sqlalchemy
|
|
23
23
|
from epyxid import XID
|
|
24
|
+
from langchain.agents import create_agent as create_react_agent
|
|
24
25
|
from langchain_core.language_models import BaseChatModel
|
|
25
26
|
from langchain_core.messages import (
|
|
26
27
|
BaseMessage,
|
|
@@ -29,7 +30,6 @@ from langchain_core.messages import (
|
|
|
29
30
|
from langchain_core.tools import BaseTool
|
|
30
31
|
from langgraph.errors import GraphRecursionError
|
|
31
32
|
from langgraph.graph.state import CompiledStateGraph
|
|
32
|
-
from langgraph.prebuilt import create_react_agent
|
|
33
33
|
from langgraph.runtime import Runtime
|
|
34
34
|
from sqlalchemy import func, update
|
|
35
35
|
from sqlalchemy.exc import SQLAlchemyError
|
|
@@ -56,7 +56,7 @@ from intentkit.models.chat import (
|
|
|
56
56
|
from intentkit.models.credit import CreditAccount, OwnerType
|
|
57
57
|
from intentkit.models.db import get_langgraph_checkpointer, get_session
|
|
58
58
|
from intentkit.models.llm import LLMModelInfo, LLMProvider, create_llm_model
|
|
59
|
-
from intentkit.models.skill import AgentSkillData,
|
|
59
|
+
from intentkit.models.skill import AgentSkillData, ChatSkillData
|
|
60
60
|
from intentkit.models.user import User
|
|
61
61
|
from intentkit.utils.error import IntentKitAPIError
|
|
62
62
|
|
|
@@ -70,7 +70,9 @@ _agents: dict[str, CompiledStateGraph] = {}
|
|
|
70
70
|
_agents_updated: dict[str, datetime] = {}
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
async def build_agent(
|
|
73
|
+
async def build_agent(
|
|
74
|
+
agent: Agent, agent_data: AgentData, custom_skills: list[BaseTool] = []
|
|
75
|
+
) -> CompiledStateGraph:
|
|
74
76
|
"""Build an AI agent with specified configuration and tools.
|
|
75
77
|
|
|
76
78
|
This function:
|
|
@@ -82,7 +84,8 @@ async def build_agent(agent: Agent, agent_data: AgentData) -> CompiledStateGraph
|
|
|
82
84
|
Args:
|
|
83
85
|
agent (Agent): Agent configuration object
|
|
84
86
|
agent_data (AgentData): Agent data object
|
|
85
|
-
|
|
87
|
+
custom_skills (list[BaseTool], optional): Designed for advanced user who directly
|
|
88
|
+
call this function to inject custom skills into the agent tool node.
|
|
86
89
|
|
|
87
90
|
Returns:
|
|
88
91
|
CompiledStateGraph: Initialized LangChain agent
|
|
@@ -127,6 +130,10 @@ async def build_agent(agent: Agent, agent_data: AgentData) -> CompiledStateGraph
|
|
|
127
130
|
except ImportError as e:
|
|
128
131
|
logger.error(f"Could not import skill module: {k} ({e})")
|
|
129
132
|
|
|
133
|
+
# add custom skills to private tools
|
|
134
|
+
if custom_skills and len(custom_skills) > 0:
|
|
135
|
+
private_tools.extend(custom_skills)
|
|
136
|
+
|
|
130
137
|
# filter the duplicate tools
|
|
131
138
|
tools = list({tool.name: tool for tool in tools}.values())
|
|
132
139
|
private_tools = list({tool.name: tool for tool in private_tools}.values())
|
|
@@ -889,7 +896,7 @@ async def clean_agent_memory(
|
|
|
889
896
|
|
|
890
897
|
if clean_skill:
|
|
891
898
|
await AgentSkillData.clean_data(agent_id)
|
|
892
|
-
await
|
|
899
|
+
await ChatSkillData.clean_data(agent_id, chat_id)
|
|
893
900
|
|
|
894
901
|
async with get_session() as db:
|
|
895
902
|
if clean_agent:
|
intentkit/models/skill.py
CHANGED
|
@@ -213,12 +213,12 @@ class AgentSkillData(AgentSkillDataCreate):
|
|
|
213
213
|
await db.commit()
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
class
|
|
217
|
-
"""Database table model for storing skill-specific data for
|
|
216
|
+
class ChatSkillDataTable(Base):
|
|
217
|
+
"""Database table model for storing skill-specific data for chats."""
|
|
218
218
|
|
|
219
|
-
__tablename__ = "
|
|
219
|
+
__tablename__ = "chat_skill_data"
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
chat_id = Column(String, primary_key=True)
|
|
222
222
|
skill = Column(String, primary_key=True)
|
|
223
223
|
key = Column(String, primary_key=True)
|
|
224
224
|
agent_id = Column(String, nullable=False)
|
|
@@ -236,31 +236,29 @@ class ThreadSkillDataTable(Base):
|
|
|
236
236
|
)
|
|
237
237
|
|
|
238
238
|
|
|
239
|
-
class
|
|
240
|
-
"""Base model for creating
|
|
239
|
+
class ChatSkillDataCreate(BaseModel):
|
|
240
|
+
"""Base model for creating chat skill data records."""
|
|
241
241
|
|
|
242
242
|
model_config = ConfigDict(from_attributes=True)
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
str, Field(description="ID of the thread this data belongs to")
|
|
246
|
-
]
|
|
244
|
+
chat_id: Annotated[str, Field(description="ID of the chat this data belongs to")]
|
|
247
245
|
skill: Annotated[str, Field(description="Name of the skill this data is for")]
|
|
248
246
|
key: Annotated[str, Field(description="Key for this specific piece of data")]
|
|
249
|
-
agent_id: Annotated[str, Field(description="ID of the agent that owns this
|
|
247
|
+
agent_id: Annotated[str, Field(description="ID of the agent that owns this chat")]
|
|
250
248
|
data: Annotated[Dict[str, Any], Field(description="JSON data stored for this key")]
|
|
251
249
|
|
|
252
|
-
async def save(self) -> "
|
|
250
|
+
async def save(self) -> "ChatSkillData":
|
|
253
251
|
"""Save or update skill data.
|
|
254
252
|
|
|
255
253
|
Returns:
|
|
256
|
-
|
|
254
|
+
ChatSkillData: The saved chat skill data instance
|
|
257
255
|
"""
|
|
258
256
|
async with get_session() as db:
|
|
259
257
|
record = await db.scalar(
|
|
260
|
-
select(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
258
|
+
select(ChatSkillDataTable).where(
|
|
259
|
+
ChatSkillDataTable.chat_id == self.chat_id,
|
|
260
|
+
ChatSkillDataTable.skill == self.skill,
|
|
261
|
+
ChatSkillDataTable.key == self.key,
|
|
264
262
|
)
|
|
265
263
|
)
|
|
266
264
|
|
|
@@ -270,18 +268,18 @@ class ThreadSkillDataCreate(BaseModel):
|
|
|
270
268
|
record.agent_id = self.agent_id
|
|
271
269
|
else:
|
|
272
270
|
# Create new record
|
|
273
|
-
record =
|
|
271
|
+
record = ChatSkillDataTable(**self.model_dump())
|
|
274
272
|
db.add(record)
|
|
275
273
|
await db.commit()
|
|
276
274
|
await db.refresh(record)
|
|
277
|
-
return
|
|
275
|
+
return ChatSkillData.model_validate(record)
|
|
278
276
|
|
|
279
277
|
|
|
280
|
-
class
|
|
281
|
-
"""Model for storing skill-specific data for
|
|
278
|
+
class ChatSkillData(ChatSkillDataCreate):
|
|
279
|
+
"""Model for storing skill-specific data for chats.
|
|
282
280
|
|
|
283
|
-
This model uses a composite primary key of (
|
|
284
|
-
skill-specific data for
|
|
281
|
+
This model uses a composite primary key of (chat_id, skill, key) to store
|
|
282
|
+
skill-specific data for chats in a flexible way. It also includes agent_id
|
|
285
283
|
as a required field for tracking ownership.
|
|
286
284
|
"""
|
|
287
285
|
|
|
@@ -298,11 +296,11 @@ class ThreadSkillData(ThreadSkillDataCreate):
|
|
|
298
296
|
]
|
|
299
297
|
|
|
300
298
|
@classmethod
|
|
301
|
-
async def get(cls,
|
|
302
|
-
"""Get skill data for a
|
|
299
|
+
async def get(cls, chat_id: str, skill: str, key: str) -> Optional[dict]:
|
|
300
|
+
"""Get skill data for a chat.
|
|
303
301
|
|
|
304
302
|
Args:
|
|
305
|
-
|
|
303
|
+
chat_id: ID of the chat
|
|
306
304
|
skill: Name of the skill
|
|
307
305
|
key: Data key
|
|
308
306
|
|
|
@@ -311,10 +309,10 @@ class ThreadSkillData(ThreadSkillDataCreate):
|
|
|
311
309
|
"""
|
|
312
310
|
async with get_session() as db:
|
|
313
311
|
record = await db.scalar(
|
|
314
|
-
select(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
312
|
+
select(ChatSkillDataTable).where(
|
|
313
|
+
ChatSkillDataTable.chat_id == chat_id,
|
|
314
|
+
ChatSkillDataTable.skill == skill,
|
|
315
|
+
ChatSkillDataTable.key == key,
|
|
318
316
|
)
|
|
319
317
|
)
|
|
320
318
|
return record.data if record else None
|
|
@@ -323,33 +321,33 @@ class ThreadSkillData(ThreadSkillDataCreate):
|
|
|
323
321
|
async def clean_data(
|
|
324
322
|
cls,
|
|
325
323
|
agent_id: str,
|
|
326
|
-
|
|
324
|
+
chat_id: Annotated[
|
|
327
325
|
str,
|
|
328
326
|
Field(
|
|
329
327
|
default="",
|
|
330
|
-
description="Optional ID of the
|
|
328
|
+
description="Optional ID of the chat. If provided, only cleans data for that chat.",
|
|
331
329
|
),
|
|
332
330
|
],
|
|
333
331
|
):
|
|
334
|
-
"""Clean all skill data for a
|
|
332
|
+
"""Clean all skill data for a chat or agent.
|
|
335
333
|
|
|
336
334
|
Args:
|
|
337
335
|
agent_id: ID of the agent
|
|
338
|
-
|
|
339
|
-
|
|
336
|
+
chat_id: Optional ID of the chat. If provided, only cleans data for that chat.
|
|
337
|
+
If empty, cleans all data for the agent.
|
|
340
338
|
"""
|
|
341
339
|
async with get_session() as db:
|
|
342
|
-
if
|
|
340
|
+
if chat_id and chat_id != "":
|
|
343
341
|
await db.execute(
|
|
344
|
-
delete(
|
|
345
|
-
|
|
346
|
-
|
|
342
|
+
delete(ChatSkillDataTable).where(
|
|
343
|
+
ChatSkillDataTable.agent_id == agent_id,
|
|
344
|
+
ChatSkillDataTable.chat_id == chat_id,
|
|
347
345
|
)
|
|
348
346
|
)
|
|
349
347
|
else:
|
|
350
348
|
await db.execute(
|
|
351
|
-
delete(
|
|
352
|
-
|
|
349
|
+
delete(ChatSkillDataTable).where(
|
|
350
|
+
ChatSkillDataTable.agent_id == agent_id
|
|
353
351
|
)
|
|
354
352
|
)
|
|
355
353
|
await db.commit()
|
intentkit/skills/base.py
CHANGED
|
@@ -33,6 +33,12 @@ from intentkit.abstracts.skill import SkillStoreABC
|
|
|
33
33
|
from intentkit.clients import get_wallet_provider
|
|
34
34
|
from intentkit.clients.web3 import get_web3_client
|
|
35
35
|
from intentkit.models.redis import get_redis
|
|
36
|
+
from intentkit.models.skill import (
|
|
37
|
+
AgentSkillData,
|
|
38
|
+
AgentSkillDataCreate,
|
|
39
|
+
ChatSkillData,
|
|
40
|
+
ChatSkillDataCreate,
|
|
41
|
+
)
|
|
36
42
|
from intentkit.utils.error import IntentKitAPIError, RateLimitExceeded
|
|
37
43
|
|
|
38
44
|
if TYPE_CHECKING:
|
|
@@ -184,6 +190,67 @@ class IntentKitSkill(BaseTool):
|
|
|
184
190
|
|
|
185
191
|
return get_web3_client(network_id)
|
|
186
192
|
|
|
193
|
+
async def get_agent_skill_data(
|
|
194
|
+
self,
|
|
195
|
+
key: str,
|
|
196
|
+
) -> Optional[Dict[str, Any]]:
|
|
197
|
+
"""Retrieve persisted data for this skill scoped to the active agent."""
|
|
198
|
+
return await self.get_agent_skill_data_raw(self.name, key)
|
|
199
|
+
|
|
200
|
+
async def get_agent_skill_data_raw(
|
|
201
|
+
self,
|
|
202
|
+
skill_name: str,
|
|
203
|
+
key: str,
|
|
204
|
+
) -> Optional[Dict[str, Any]]:
|
|
205
|
+
"""Retrieve persisted data for a specific skill scoped to the active agent."""
|
|
206
|
+
context = self.get_context()
|
|
207
|
+
return await AgentSkillData.get(context.agent_id, skill_name, key)
|
|
208
|
+
|
|
209
|
+
async def save_agent_skill_data(self, key: str, data: Dict[str, Any]) -> None:
|
|
210
|
+
"""Persist data for this skill scoped to the active agent."""
|
|
211
|
+
await self.save_agent_skill_data_raw(self.name, key, data)
|
|
212
|
+
|
|
213
|
+
async def save_agent_skill_data_raw(
|
|
214
|
+
self,
|
|
215
|
+
skill_name: str,
|
|
216
|
+
key: str,
|
|
217
|
+
data: Dict[str, Any],
|
|
218
|
+
) -> None:
|
|
219
|
+
"""Persist data for a specific skill scoped to the active agent."""
|
|
220
|
+
context = self.get_context()
|
|
221
|
+
skill_data = AgentSkillDataCreate(
|
|
222
|
+
agent_id=context.agent_id,
|
|
223
|
+
skill=skill_name,
|
|
224
|
+
key=key,
|
|
225
|
+
data=data,
|
|
226
|
+
)
|
|
227
|
+
await skill_data.save()
|
|
228
|
+
|
|
229
|
+
async def delete_agent_skill_data(self, key: str) -> None:
|
|
230
|
+
"""Remove persisted data for this skill scoped to the active agent."""
|
|
231
|
+
context = self.get_context()
|
|
232
|
+
await AgentSkillData.delete(context.agent_id, self.name, key)
|
|
233
|
+
|
|
234
|
+
async def get_thread_skill_data(
|
|
235
|
+
self,
|
|
236
|
+
key: str,
|
|
237
|
+
) -> Optional[Dict[str, Any]]:
|
|
238
|
+
"""Retrieve persisted data for this skill scoped to the active chat."""
|
|
239
|
+
context = self.get_context()
|
|
240
|
+
return await ChatSkillData.get(context.chat_id, self.name, key)
|
|
241
|
+
|
|
242
|
+
async def save_thread_skill_data(self, key: str, data: Dict[str, Any]) -> None:
|
|
243
|
+
"""Persist data for this skill scoped to the active chat."""
|
|
244
|
+
context = self.get_context()
|
|
245
|
+
skill_data = ChatSkillDataCreate(
|
|
246
|
+
chat_id=context.chat_id,
|
|
247
|
+
agent_id=context.agent_id,
|
|
248
|
+
skill=self.name,
|
|
249
|
+
key=key,
|
|
250
|
+
data=data,
|
|
251
|
+
)
|
|
252
|
+
await skill_data.save()
|
|
253
|
+
|
|
187
254
|
|
|
188
255
|
async def get_agentkit_actions(
|
|
189
256
|
agent_id: str,
|
|
@@ -68,8 +68,8 @@ class CasinoDeckDraw(CasinoBaseTool):
|
|
|
68
68
|
count = validate_card_count(count)
|
|
69
69
|
|
|
70
70
|
# Get current deck info
|
|
71
|
-
deck_info = await self.
|
|
72
|
-
|
|
71
|
+
deck_info = await self.get_agent_skill_data_raw(
|
|
72
|
+
DECK_STORAGE_KEY, CURRENT_DECK_KEY
|
|
73
73
|
)
|
|
74
74
|
|
|
75
75
|
deck_id = "new" # Default to new deck
|
|
@@ -99,8 +99,7 @@ class CasinoDeckDraw(CasinoBaseTool):
|
|
|
99
99
|
else:
|
|
100
100
|
deck_info["remaining"] = data["remaining"]
|
|
101
101
|
|
|
102
|
-
await self.
|
|
103
|
-
context.agent_id,
|
|
102
|
+
await self.save_agent_skill_data_raw(
|
|
104
103
|
DECK_STORAGE_KEY,
|
|
105
104
|
CURRENT_DECK_KEY,
|
|
106
105
|
deck_info,
|
|
@@ -95,8 +95,10 @@ class CasinoDeckShuffle(CasinoBaseTool):
|
|
|
95
95
|
"shuffled": data["shuffled"],
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
await self.
|
|
99
|
-
|
|
98
|
+
await self.save_agent_skill_data_raw(
|
|
99
|
+
DECK_STORAGE_KEY,
|
|
100
|
+
CURRENT_DECK_KEY,
|
|
101
|
+
deck_info,
|
|
100
102
|
)
|
|
101
103
|
|
|
102
104
|
return {
|
|
@@ -36,22 +36,17 @@ class CryptoCompareBaseTool(IntentKitSkill):
|
|
|
36
36
|
def category(self) -> str:
|
|
37
37
|
return "cryptocompare"
|
|
38
38
|
|
|
39
|
-
async def check_rate_limit(
|
|
40
|
-
self, agent_id: str, max_requests: int = 1, interval: int = 15
|
|
41
|
-
) -> None:
|
|
39
|
+
async def check_rate_limit(self, max_requests: int = 1, interval: int = 15) -> None:
|
|
42
40
|
"""Check if the rate limit has been exceeded.
|
|
43
41
|
|
|
44
42
|
Args:
|
|
45
|
-
agent_id: The ID of the agent.
|
|
46
43
|
max_requests: Maximum number of requests allowed within the rate limit window.
|
|
47
44
|
interval: Time interval in minutes for the rate limit window.
|
|
48
45
|
|
|
49
46
|
Raises:
|
|
50
47
|
RateLimitExceeded: If the rate limit has been exceeded.
|
|
51
48
|
"""
|
|
52
|
-
rate_limit = await self.
|
|
53
|
-
agent_id, self.name, "rate_limit"
|
|
54
|
-
)
|
|
49
|
+
rate_limit = await self.get_agent_skill_data("rate_limit")
|
|
55
50
|
|
|
56
51
|
current_time = datetime.now(tz=timezone.utc)
|
|
57
52
|
|
|
@@ -65,9 +60,7 @@ class CryptoCompareBaseTool(IntentKitSkill):
|
|
|
65
60
|
raise RateLimitExceeded("Rate limit exceeded")
|
|
66
61
|
|
|
67
62
|
rate_limit["count"] += 1
|
|
68
|
-
await self.
|
|
69
|
-
agent_id, self.name, "rate_limit", rate_limit
|
|
70
|
-
)
|
|
63
|
+
await self.save_agent_skill_data("rate_limit", rate_limit)
|
|
71
64
|
|
|
72
65
|
return
|
|
73
66
|
|
|
@@ -76,9 +69,7 @@ class CryptoCompareBaseTool(IntentKitSkill):
|
|
|
76
69
|
"count": 1,
|
|
77
70
|
"reset_time": (current_time + timedelta(minutes=interval)).isoformat(),
|
|
78
71
|
}
|
|
79
|
-
await self.
|
|
80
|
-
agent_id, self.name, "rate_limit", new_rate_limit
|
|
81
|
-
)
|
|
72
|
+
await self.save_agent_skill_data("rate_limit", new_rate_limit)
|
|
82
73
|
return
|
|
83
74
|
|
|
84
75
|
async def fetch_price(
|
|
@@ -56,7 +56,7 @@ class CryptoCompareFetchNews(CryptoCompareBaseTool):
|
|
|
56
56
|
skill_config = context.agent.skill_config(self.category)
|
|
57
57
|
|
|
58
58
|
# Check rate limit
|
|
59
|
-
await self.check_rate_limit(
|
|
59
|
+
await self.check_rate_limit(max_requests=5, interval=60)
|
|
60
60
|
|
|
61
61
|
# Get API key from context
|
|
62
62
|
api_key = skill_config.get("api_key")
|
|
@@ -66,7 +66,7 @@ class CryptoCompareFetchPrice(CryptoCompareBaseTool):
|
|
|
66
66
|
skill_config = context.agent.skill_config(self.category)
|
|
67
67
|
|
|
68
68
|
# Check rate limit
|
|
69
|
-
await self.check_rate_limit(
|
|
69
|
+
await self.check_rate_limit(max_requests=10, interval=60)
|
|
70
70
|
|
|
71
71
|
# Get API key from context
|
|
72
72
|
api_key = skill_config.get("api_key")
|
|
@@ -72,7 +72,7 @@ class CryptoCompareFetchTopExchanges(CryptoCompareBaseTool):
|
|
|
72
72
|
skill_config = context.agent.skill_config(self.category)
|
|
73
73
|
|
|
74
74
|
# Check rate limit
|
|
75
|
-
await self.check_rate_limit(
|
|
75
|
+
await self.check_rate_limit(max_requests=5, interval=60)
|
|
76
76
|
|
|
77
77
|
# Get API key from context
|
|
78
78
|
api_key = skill_config.get("api_key")
|
|
@@ -65,7 +65,7 @@ class CryptoCompareFetchTopMarketCap(CryptoCompareBaseTool):
|
|
|
65
65
|
skill_config = context.agent.skill_config(self.category)
|
|
66
66
|
|
|
67
67
|
# Check rate limit
|
|
68
|
-
await self.check_rate_limit(
|
|
68
|
+
await self.check_rate_limit(max_requests=5, interval=60)
|
|
69
69
|
|
|
70
70
|
# Get API key from context
|
|
71
71
|
api_key = skill_config.get("api_key")
|
|
@@ -64,7 +64,7 @@ class CryptoCompareFetchTopVolume(CryptoCompareBaseTool):
|
|
|
64
64
|
skill_config = context.agent.skill_config(self.category)
|
|
65
65
|
|
|
66
66
|
# Check rate limit
|
|
67
|
-
await self.check_rate_limit(
|
|
67
|
+
await self.check_rate_limit(max_requests=5, interval=60)
|
|
68
68
|
|
|
69
69
|
# Get API key from context
|
|
70
70
|
api_key = skill_config.get("api_key")
|
|
@@ -67,7 +67,7 @@ class CryptoCompareFetchTradingSignals(CryptoCompareBaseTool):
|
|
|
67
67
|
skill_config = context.agent.skill_config(self.category)
|
|
68
68
|
|
|
69
69
|
# Check rate limit
|
|
70
|
-
await self.check_rate_limit(
|
|
70
|
+
await self.check_rate_limit(max_requests=5, interval=60)
|
|
71
71
|
|
|
72
72
|
# Get API key from context
|
|
73
73
|
api_key = skill_config.get("api_key")
|