intentkit 0.8.6.dev2__py3-none-any.whl → 0.8.17__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.

Files changed (312) hide show
  1. intentkit/__init__.py +1 -1
  2. intentkit/abstracts/agent.py +4 -5
  3. intentkit/abstracts/engine.py +5 -5
  4. intentkit/abstracts/graph.py +10 -5
  5. intentkit/abstracts/skill.py +6 -144
  6. intentkit/abstracts/twitter.py +4 -5
  7. intentkit/clients/__init__.py +3 -2
  8. intentkit/clients/cdp.py +53 -92
  9. intentkit/clients/twitter.py +56 -57
  10. intentkit/clients/web3.py +1 -3
  11. intentkit/config/config.py +5 -0
  12. intentkit/core/agent.py +16 -388
  13. intentkit/core/asset.py +64 -18
  14. intentkit/core/client.py +1 -1
  15. intentkit/core/credit.py +19 -20
  16. intentkit/core/engine.py +26 -11
  17. intentkit/core/node.py +2 -1
  18. intentkit/core/prompt.py +53 -15
  19. intentkit/core/scheduler.py +9 -9
  20. intentkit/core/statistics.py +6 -7
  21. intentkit/models/agent.py +256 -176
  22. intentkit/models/agent_data.py +62 -36
  23. intentkit/models/agent_schema.json +6 -9
  24. intentkit/models/app_setting.py +6 -6
  25. intentkit/models/chat.py +28 -24
  26. intentkit/models/conversation.py +8 -8
  27. intentkit/models/credit.py +62 -64
  28. intentkit/models/db.py +8 -7
  29. intentkit/models/db_mig.py +2 -2
  30. intentkit/models/llm.csv +15 -12
  31. intentkit/models/llm.py +18 -16
  32. intentkit/models/redis.py +2 -3
  33. intentkit/models/skill.py +62 -66
  34. intentkit/models/skills.csv +30 -26
  35. intentkit/models/user.py +46 -21
  36. intentkit/skills/acolyt/__init__.py +2 -9
  37. intentkit/skills/acolyt/ask.py +3 -4
  38. intentkit/skills/acolyt/base.py +4 -9
  39. intentkit/skills/aixbt/__init__.py +2 -13
  40. intentkit/skills/aixbt/base.py +1 -7
  41. intentkit/skills/aixbt/projects.py +14 -15
  42. intentkit/skills/allora/__init__.py +2 -9
  43. intentkit/skills/allora/base.py +4 -9
  44. intentkit/skills/allora/price.py +3 -4
  45. intentkit/skills/base.py +175 -52
  46. intentkit/skills/basename/__init__.py +4 -8
  47. intentkit/skills/carv/__init__.py +115 -121
  48. intentkit/skills/carv/base.py +184 -185
  49. intentkit/skills/carv/fetch_news.py +3 -3
  50. intentkit/skills/carv/onchain_query.py +4 -4
  51. intentkit/skills/carv/token_info_and_price.py +5 -5
  52. intentkit/skills/casino/__init__.py +4 -15
  53. intentkit/skills/casino/base.py +1 -7
  54. intentkit/skills/casino/deck_draw.py +5 -8
  55. intentkit/skills/casino/deck_shuffle.py +6 -6
  56. intentkit/skills/casino/dice_roll.py +2 -4
  57. intentkit/skills/cdp/__init__.py +3 -10
  58. intentkit/skills/cdp/base.py +1 -7
  59. intentkit/skills/cdp/schema.json +1 -17
  60. intentkit/skills/chainlist/__init__.py +2 -7
  61. intentkit/skills/chainlist/base.py +1 -7
  62. intentkit/skills/chainlist/chain_lookup.py +18 -18
  63. intentkit/skills/common/__init__.py +2 -9
  64. intentkit/skills/common/base.py +1 -7
  65. intentkit/skills/common/current_time.py +1 -2
  66. intentkit/skills/cookiefun/__init__.py +6 -9
  67. intentkit/skills/cookiefun/base.py +2 -7
  68. intentkit/skills/cookiefun/get_account_details.py +7 -7
  69. intentkit/skills/cookiefun/get_account_feed.py +19 -19
  70. intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
  71. intentkit/skills/cookiefun/get_sectors.py +3 -3
  72. intentkit/skills/cookiefun/search_accounts.py +9 -9
  73. intentkit/skills/cryptocompare/__init__.py +7 -24
  74. intentkit/skills/cryptocompare/api.py +2 -3
  75. intentkit/skills/cryptocompare/base.py +10 -24
  76. intentkit/skills/cryptocompare/fetch_news.py +4 -5
  77. intentkit/skills/cryptocompare/fetch_price.py +6 -7
  78. intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
  79. intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
  80. intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
  81. intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
  82. intentkit/skills/cryptopanic/__init__.py +7 -10
  83. intentkit/skills/cryptopanic/base.py +51 -55
  84. intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
  85. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
  86. intentkit/skills/dapplooker/__init__.py +2 -9
  87. intentkit/skills/dapplooker/base.py +4 -9
  88. intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
  89. intentkit/skills/defillama/__init__.py +24 -74
  90. intentkit/skills/defillama/api.py +6 -9
  91. intentkit/skills/defillama/base.py +8 -19
  92. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
  93. intentkit/skills/defillama/coins/fetch_block.py +6 -8
  94. intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
  95. intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
  96. intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
  97. intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
  98. intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
  99. intentkit/skills/defillama/config/chains.py +1 -3
  100. intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
  101. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
  102. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
  103. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
  104. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
  105. intentkit/skills/defillama/tests/api_integration.test.py +1 -1
  106. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
  107. intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
  108. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
  109. intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
  110. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
  111. intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
  112. intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
  113. intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
  114. intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
  115. intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
  116. intentkit/skills/defillama/yields/fetch_pools.py +26 -30
  117. intentkit/skills/dexscreener/__init__.py +97 -102
  118. intentkit/skills/dexscreener/base.py +125 -130
  119. intentkit/skills/dexscreener/get_pair_info.py +4 -5
  120. intentkit/skills/dexscreener/get_token_pairs.py +4 -5
  121. intentkit/skills/dexscreener/get_tokens_info.py +7 -8
  122. intentkit/skills/dexscreener/model/search_token_response.py +80 -82
  123. intentkit/skills/dexscreener/search_token.py +182 -184
  124. intentkit/skills/dexscreener/utils.py +15 -14
  125. intentkit/skills/dune_analytics/__init__.py +7 -9
  126. intentkit/skills/dune_analytics/base.py +48 -52
  127. intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
  128. intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
  129. intentkit/skills/elfa/__init__.py +5 -18
  130. intentkit/skills/elfa/base.py +10 -14
  131. intentkit/skills/elfa/mention.py +19 -21
  132. intentkit/skills/elfa/stats.py +4 -4
  133. intentkit/skills/elfa/tokens.py +12 -12
  134. intentkit/skills/elfa/utils.py +26 -28
  135. intentkit/skills/enso/__init__.py +11 -31
  136. intentkit/skills/enso/base.py +9 -15
  137. intentkit/skills/enso/best_yield.py +5 -7
  138. intentkit/skills/enso/networks.py +3 -9
  139. intentkit/skills/enso/prices.py +2 -4
  140. intentkit/skills/enso/route.py +6 -12
  141. intentkit/skills/enso/tokens.py +4 -16
  142. intentkit/skills/enso/wallet.py +6 -6
  143. intentkit/skills/erc20/__init__.py +5 -11
  144. intentkit/skills/erc721/__init__.py +5 -9
  145. intentkit/skills/firecrawl/__init__.py +5 -18
  146. intentkit/skills/firecrawl/base.py +4 -9
  147. intentkit/skills/firecrawl/clear.py +4 -8
  148. intentkit/skills/firecrawl/crawl.py +19 -19
  149. intentkit/skills/firecrawl/query.py +4 -3
  150. intentkit/skills/firecrawl/scrape.py +17 -22
  151. intentkit/skills/firecrawl/utils.py +50 -42
  152. intentkit/skills/github/__init__.py +2 -7
  153. intentkit/skills/github/base.py +1 -7
  154. intentkit/skills/github/github_search.py +1 -2
  155. intentkit/skills/heurist/__init__.py +8 -27
  156. intentkit/skills/heurist/base.py +4 -9
  157. intentkit/skills/heurist/image_generation_animagine_xl.py +12 -13
  158. intentkit/skills/heurist/image_generation_arthemy_comics.py +12 -13
  159. intentkit/skills/heurist/image_generation_arthemy_real.py +12 -13
  160. intentkit/skills/heurist/image_generation_braindance.py +12 -13
  161. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +12 -13
  162. intentkit/skills/heurist/image_generation_flux_1_dev.py +12 -13
  163. intentkit/skills/heurist/image_generation_sdxl.py +12 -13
  164. intentkit/skills/http/__init__.py +4 -15
  165. intentkit/skills/http/base.py +1 -7
  166. intentkit/skills/http/get.py +21 -16
  167. intentkit/skills/http/post.py +23 -18
  168. intentkit/skills/http/put.py +23 -18
  169. intentkit/skills/lifi/__init__.py +5 -10
  170. intentkit/skills/lifi/base.py +1 -7
  171. intentkit/skills/lifi/token_execute.py +14 -17
  172. intentkit/skills/lifi/token_quote.py +7 -9
  173. intentkit/skills/lifi/utils.py +16 -16
  174. intentkit/skills/moralis/__init__.py +6 -10
  175. intentkit/skills/moralis/api.py +6 -7
  176. intentkit/skills/moralis/base.py +5 -10
  177. intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
  178. intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
  179. intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
  180. intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
  181. intentkit/skills/morpho/__init__.py +5 -9
  182. intentkit/skills/nation/__init__.py +4 -9
  183. intentkit/skills/nation/base.py +5 -10
  184. intentkit/skills/nation/nft_check.py +3 -4
  185. intentkit/skills/onchain.py +23 -0
  186. intentkit/skills/openai/__init__.py +17 -18
  187. intentkit/skills/openai/base.py +10 -14
  188. intentkit/skills/openai/dalle_image_generation.py +3 -8
  189. intentkit/skills/openai/gpt_avatar_generator.py +102 -0
  190. intentkit/skills/openai/gpt_image_generation.py +4 -8
  191. intentkit/skills/openai/gpt_image_mini_generator.py +91 -0
  192. intentkit/skills/openai/gpt_image_to_image.py +4 -8
  193. intentkit/skills/openai/image_to_text.py +3 -7
  194. intentkit/skills/openai/schema.json +32 -0
  195. intentkit/skills/portfolio/__init__.py +11 -35
  196. intentkit/skills/portfolio/base.py +33 -19
  197. intentkit/skills/portfolio/token_balances.py +21 -21
  198. intentkit/skills/portfolio/wallet_approvals.py +17 -18
  199. intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
  200. intentkit/skills/portfolio/wallet_history.py +31 -31
  201. intentkit/skills/portfolio/wallet_net_worth.py +13 -13
  202. intentkit/skills/portfolio/wallet_nfts.py +19 -19
  203. intentkit/skills/portfolio/wallet_profitability.py +18 -18
  204. intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
  205. intentkit/skills/portfolio/wallet_stats.py +3 -3
  206. intentkit/skills/portfolio/wallet_swaps.py +19 -19
  207. intentkit/skills/pyth/__init__.py +4 -10
  208. intentkit/skills/skills.toml +4 -0
  209. intentkit/skills/slack/__init__.py +5 -17
  210. intentkit/skills/slack/base.py +3 -9
  211. intentkit/skills/slack/get_channel.py +8 -8
  212. intentkit/skills/slack/get_message.py +9 -9
  213. intentkit/skills/slack/schedule_message.py +5 -5
  214. intentkit/skills/slack/send_message.py +3 -5
  215. intentkit/skills/supabase/__init__.py +7 -23
  216. intentkit/skills/supabase/base.py +1 -7
  217. intentkit/skills/supabase/delete_data.py +4 -4
  218. intentkit/skills/supabase/fetch_data.py +12 -12
  219. intentkit/skills/supabase/insert_data.py +4 -4
  220. intentkit/skills/supabase/invoke_function.py +6 -6
  221. intentkit/skills/supabase/update_data.py +6 -6
  222. intentkit/skills/supabase/upsert_data.py +4 -4
  223. intentkit/skills/superfluid/__init__.py +5 -9
  224. intentkit/skills/system/__init__.py +7 -24
  225. intentkit/skills/system/add_autonomous_task.py +10 -12
  226. intentkit/skills/system/delete_autonomous_task.py +2 -2
  227. intentkit/skills/system/edit_autonomous_task.py +14 -18
  228. intentkit/skills/system/list_autonomous_tasks.py +3 -5
  229. intentkit/skills/system/read_agent_api_key.py +6 -4
  230. intentkit/skills/system/regenerate_agent_api_key.py +6 -4
  231. intentkit/skills/tavily/__init__.py +3 -12
  232. intentkit/skills/tavily/base.py +4 -9
  233. intentkit/skills/tavily/tavily_extract.py +2 -4
  234. intentkit/skills/tavily/tavily_search.py +4 -6
  235. intentkit/skills/token/__init__.py +5 -10
  236. intentkit/skills/token/base.py +7 -11
  237. intentkit/skills/token/erc20_transfers.py +19 -19
  238. intentkit/skills/token/token_analytics.py +3 -3
  239. intentkit/skills/token/token_price.py +13 -13
  240. intentkit/skills/token/token_search.py +9 -9
  241. intentkit/skills/twitter/__init__.py +11 -35
  242. intentkit/skills/twitter/base.py +22 -34
  243. intentkit/skills/twitter/follow_user.py +2 -6
  244. intentkit/skills/twitter/get_mentions.py +5 -12
  245. intentkit/skills/twitter/get_timeline.py +4 -12
  246. intentkit/skills/twitter/get_user_by_username.py +2 -6
  247. intentkit/skills/twitter/get_user_tweets.py +5 -13
  248. intentkit/skills/twitter/like_tweet.py +2 -6
  249. intentkit/skills/twitter/post_tweet.py +6 -9
  250. intentkit/skills/twitter/reply_tweet.py +6 -9
  251. intentkit/skills/twitter/retweet.py +2 -6
  252. intentkit/skills/twitter/search_tweets.py +4 -12
  253. intentkit/skills/unrealspeech/__init__.py +2 -7
  254. intentkit/skills/unrealspeech/base.py +2 -8
  255. intentkit/skills/unrealspeech/text_to_speech.py +8 -8
  256. intentkit/skills/venice_audio/__init__.py +98 -106
  257. intentkit/skills/venice_audio/base.py +117 -121
  258. intentkit/skills/venice_audio/input.py +41 -41
  259. intentkit/skills/venice_audio/venice_audio.py +7 -11
  260. intentkit/skills/venice_image/__init__.py +147 -154
  261. intentkit/skills/venice_image/api.py +138 -138
  262. intentkit/skills/venice_image/base.py +185 -192
  263. intentkit/skills/venice_image/config.py +33 -35
  264. intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
  265. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
  266. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
  267. intentkit/skills/venice_image/image_generation/image_generation_base.py +9 -9
  268. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
  269. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
  270. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
  271. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
  272. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
  273. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
  274. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
  275. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
  276. intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
  277. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
  278. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
  279. intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
  280. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
  281. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
  282. intentkit/skills/venice_image/utils.py +77 -78
  283. intentkit/skills/web_scraper/__init__.py +5 -18
  284. intentkit/skills/web_scraper/base.py +21 -7
  285. intentkit/skills/web_scraper/document_indexer.py +7 -6
  286. intentkit/skills/web_scraper/scrape_and_index.py +15 -15
  287. intentkit/skills/web_scraper/utils.py +62 -63
  288. intentkit/skills/web_scraper/website_indexer.py +17 -19
  289. intentkit/skills/weth/__init__.py +5 -11
  290. intentkit/skills/wow/__init__.py +5 -11
  291. intentkit/skills/x402/__init__.py +61 -0
  292. intentkit/skills/x402/ask_agent.py +98 -0
  293. intentkit/skills/x402/base.py +99 -0
  294. intentkit/skills/x402/http_request.py +117 -0
  295. intentkit/skills/x402/schema.json +45 -0
  296. intentkit/skills/x402/x402.webp +0 -0
  297. intentkit/skills/xmtp/__init__.py +4 -15
  298. intentkit/skills/xmtp/base.py +5 -5
  299. intentkit/skills/xmtp/price.py +6 -6
  300. intentkit/skills/xmtp/swap.py +6 -8
  301. intentkit/skills/xmtp/transfer.py +4 -6
  302. intentkit/utils/error.py +2 -2
  303. intentkit/utils/logging.py +2 -4
  304. intentkit/utils/s3.py +8 -9
  305. intentkit/utils/schema.py +100 -0
  306. intentkit/utils/slack_alert.py +7 -8
  307. {intentkit-0.8.6.dev2.dist-info → intentkit-0.8.17.dist-info}/METADATA +3 -4
  308. intentkit-0.8.17.dist-info/RECORD +466 -0
  309. intentkit/models/generator.py +0 -347
  310. intentkit-0.8.6.dev2.dist-info/RECORD +0 -457
  311. {intentkit-0.8.6.dev2.dist-info → intentkit-0.8.17.dist-info}/WHEEL +0 -0
  312. {intentkit-0.8.6.dev2.dist-info → intentkit-0.8.17.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,5 @@
1
1
  from typing import TypedDict
2
2
 
3
- from intentkit.abstracts.skill import SkillStoreABC
4
3
  from intentkit.skills.aixbt.base import AIXBTBaseTool
5
4
  from intentkit.skills.aixbt.projects import AIXBTProjects
6
5
  from intentkit.skills.base import SkillConfig, SkillState
@@ -27,7 +26,6 @@ class Config(SkillConfig):
27
26
  async def get_skills(
28
27
  config: "Config",
29
28
  is_private: bool,
30
- store: SkillStoreABC,
31
29
  **_,
32
30
  ) -> list[AIXBTBaseTool]:
33
31
  """Get all AIXBT API skills."""
@@ -44,26 +42,17 @@ async def get_skills(
44
42
  available_skills.append(skill_name)
45
43
 
46
44
  # Get each skill using the cached getter
47
- return [
48
- get_aixbt_skill(
49
- name=name,
50
- store=store,
51
- )
52
- for name in available_skills
53
- ]
45
+ return [get_aixbt_skill(name) for name in available_skills]
54
46
 
55
47
 
56
48
  def get_aixbt_skill(
57
49
  name: str,
58
- store: SkillStoreABC,
59
50
  ) -> AIXBTBaseTool:
60
51
  """Get an AIXBT API skill by name."""
61
52
 
62
53
  if name == "aixbt_projects":
63
54
  if name not in _cache:
64
- _cache[name] = AIXBTProjects(
65
- skill_store=store,
66
- )
55
+ _cache[name] = AIXBTProjects()
67
56
  return _cache[name]
68
57
  else:
69
58
  raise ValueError(f"Unknown AIXBT skill: {name}")
@@ -1,8 +1,5 @@
1
- from typing import Type
2
-
3
1
  from pydantic import BaseModel, Field
4
2
 
5
- from intentkit.abstracts.skill import SkillStoreABC
6
3
  from intentkit.skills.base import IntentKitSkill
7
4
 
8
5
 
@@ -11,10 +8,7 @@ class AIXBTBaseTool(IntentKitSkill):
11
8
 
12
9
  name: str = Field(description="The name of the tool")
13
10
  description: str = Field(description="A description of what the tool does")
14
- args_schema: Type[BaseModel]
15
- skill_store: SkillStoreABC = Field(
16
- description="The skill store for persisting data"
17
- )
11
+ args_schema: type[BaseModel]
18
12
 
19
13
  @property
20
14
  def category(self) -> str:
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Dict, Optional, Type
2
+ from typing import Any
3
3
 
4
4
  import httpx
5
5
  from langchain_core.tools import ToolException
@@ -17,23 +17,23 @@ class ProjectsInput(BaseModel):
17
17
  default=10,
18
18
  description="Number of projects to return (max 50)",
19
19
  )
20
- name: Optional[str] = Field(
20
+ name: str | None = Field(
21
21
  default=None,
22
22
  description="Filter projects by name (case-insensitive regex match)",
23
23
  )
24
- ticker: Optional[str] = Field(
24
+ ticker: str | None = Field(
25
25
  default=None,
26
26
  description="Filter projects by ticker symbol (case-insensitive match)",
27
27
  )
28
- xHandle: Optional[str] = Field(
28
+ xHandle: str | None = Field(
29
29
  default=None,
30
30
  description="Filter projects by X/Twitter handle",
31
31
  )
32
- minScore: Optional[float] = Field(
32
+ minScore: float | None = Field(
33
33
  default=None,
34
34
  description="Minimum score threshold",
35
35
  )
36
- chain: Optional[str] = Field(
36
+ chain: str | None = Field(
37
37
  default=None,
38
38
  description="Filter projects by blockchain",
39
39
  )
@@ -53,18 +53,18 @@ class AIXBTProjects(AIXBTBaseTool):
53
53
  "detailed information on recent developments. The 'alpha' keyword is a trigger "
54
54
  "for accessing AIXBT's specific dataset for crypto research."
55
55
  )
56
- args_schema: Type[BaseModel] = ProjectsInput
56
+ args_schema: type[BaseModel] = ProjectsInput
57
57
 
58
58
  async def _arun(
59
59
  self,
60
60
  limit: int = 10,
61
- name: Optional[str] = None,
62
- ticker: Optional[str] = None,
63
- xHandle: Optional[str] = None,
64
- minScore: Optional[float] = None,
65
- chain: Optional[str] = None,
61
+ name: str | None = None,
62
+ ticker: str | None = None,
63
+ xHandle: str | None = None,
64
+ minScore: float | None = None,
65
+ chain: str | None = None,
66
66
  **kwargs,
67
- ) -> Dict[str, Any]:
67
+ ) -> dict[str, Any]:
68
68
  """
69
69
  Search for cryptocurrency projects using AIXBT API.
70
70
 
@@ -89,9 +89,8 @@ class AIXBTProjects(AIXBTBaseTool):
89
89
  "rate_limit_minutes"
90
90
  ):
91
91
  await self.user_rate_limit_by_category(
92
- context.user_id,
93
92
  skill_config["rate_limit_number"],
94
- skill_config["rate_limit_minutes"],
93
+ skill_config["rate_limit_minutes"] * 60,
95
94
  )
96
95
 
97
96
  # Get the API key from the agent's configuration
@@ -3,7 +3,6 @@
3
3
  import logging
4
4
  from typing import NotRequired, TypedDict
5
5
 
6
- from intentkit.abstracts.skill import SkillStoreABC
7
6
  from intentkit.skills.allora.base import AlloraBaseTool
8
7
  from intentkit.skills.allora.price import AlloraGetPrice
9
8
  from intentkit.skills.base import SkillConfig, SkillState
@@ -28,7 +27,6 @@ class Config(SkillConfig):
28
27
  async def get_skills(
29
28
  config: "Config",
30
29
  is_private: bool,
31
- store: SkillStoreABC,
32
30
  **_,
33
31
  ) -> list[AlloraBaseTool]:
34
32
  """Get all Allora skills.
@@ -36,7 +34,6 @@ async def get_skills(
36
34
  Args:
37
35
  config: The configuration for Allora skills.
38
36
  is_private: Whether to include private skills.
39
- store: The skill store for persisting data.
40
37
 
41
38
  Returns:
42
39
  A list of Allora skills.
@@ -53,7 +50,7 @@ async def get_skills(
53
50
  # Get each skill using the cached getter
54
51
  result = []
55
52
  for name in available_skills:
56
- skill = get_allora_skill(name, store)
53
+ skill = get_allora_skill(name)
57
54
  if skill:
58
55
  result.append(skill)
59
56
  return result
@@ -61,22 +58,18 @@ async def get_skills(
61
58
 
62
59
  def get_allora_skill(
63
60
  name: str,
64
- store: SkillStoreABC,
65
61
  ) -> AlloraBaseTool:
66
62
  """Get an Allora skill by name.
67
63
 
68
64
  Args:
69
65
  name: The name of the skill to get
70
- store: The skill store for persisting data
71
66
 
72
67
  Returns:
73
68
  The requested Allora skill
74
69
  """
75
70
  if name == "get_price_prediction":
76
71
  if name not in _cache:
77
- _cache[name] = AlloraGetPrice(
78
- skill_store=store,
79
- )
72
+ _cache[name] = AlloraGetPrice()
80
73
  return _cache[name]
81
74
  else:
82
75
  logger.warning(f"Unknown Allora skill: {name}")
@@ -1,9 +1,7 @@
1
- from typing import Type
2
-
3
- from langchain.tools.base import ToolException
1
+ from langchain_core.tools.base import ToolException
4
2
  from pydantic import BaseModel, Field
5
3
 
6
- from intentkit.abstracts.skill import SkillStoreABC
4
+ from intentkit.config.config import config
7
5
  from intentkit.skills.base import IntentKitSkill
8
6
 
9
7
  base_url = "https://api.upshot.xyz/v2/allora"
@@ -14,17 +12,14 @@ class AlloraBaseTool(IntentKitSkill):
14
12
 
15
13
  name: str = Field(description="The name of the tool")
16
14
  description: str = Field(description="A description of what the tool does")
17
- args_schema: Type[BaseModel]
18
- skill_store: SkillStoreABC = Field(
19
- description="The skill store for persisting data"
20
- )
15
+ args_schema: type[BaseModel]
21
16
 
22
17
  def get_api_key(self) -> str:
23
18
  context = self.get_context()
24
19
  skill_config = context.agent.skill_config(self.category)
25
20
  api_key_provider = skill_config.get("api_key_provider")
26
21
  if api_key_provider == "platform":
27
- return self.skill_store.get_system_config("allora_api_key")
22
+ return config.allora_api_key
28
23
  # for backward compatibility, may only have api_key in skill_config
29
24
  elif skill_config.get("api_key"):
30
25
  return skill_config.get("api_key")
@@ -1,7 +1,7 @@
1
- from typing import Literal, Type
1
+ from typing import Literal
2
2
 
3
3
  import httpx
4
- from langchain.tools.base import ToolException
4
+ from langchain_core.tools.base import ToolException
5
5
  from pydantic import BaseModel, Field
6
6
 
7
7
  from intentkit.skills.allora.base import AlloraBaseTool
@@ -57,7 +57,6 @@ class AlloraGetPrice(AlloraBaseTool):
57
57
  The Allora Price Prediction Feed tool fetches the price prediction feed from the Allora API.
58
58
  Ethereum (ETH) or Bitcoin (BTC) price predictions (5-minute, 8-hour)
59
59
 
60
-
61
60
  Attributes:
62
61
  name (str): Name of the tool, specifically "get_price_prediction".
63
62
  description (str): Comprehensive description of the tool's purpose and functionality.
@@ -69,7 +68,7 @@ class AlloraGetPrice(AlloraBaseTool):
69
68
  The Allora Price Prediction Feed tool fetches the price prediction feed from the Allora API.
70
69
  Ethereum (ETH) or Bitcoin (BTC) price predictions (5-minute, 8-hour)
71
70
  """
72
- args_schema: Type[BaseModel] = AlloraGetPriceInput
71
+ args_schema: type[BaseModel] = AlloraGetPriceInput
73
72
 
74
73
  def _run(self, question: str) -> AlloraGetPriceOutput:
75
74
  """Run the tool to get the token price prediction from Allora API.
intentkit/skills/base.py CHANGED
@@ -1,15 +1,10 @@
1
1
  import logging
2
- from collections.abc import Sequence
2
+ from collections.abc import Callable, Sequence
3
3
  from typing import (
4
- TYPE_CHECKING,
5
4
  Any,
6
- Callable,
7
- Dict,
8
5
  Literal,
9
6
  NotRequired,
10
- Optional,
11
7
  TypedDict,
12
- Union,
13
8
  )
14
9
 
15
10
  from coinbase_agentkit import (
@@ -18,8 +13,7 @@ from coinbase_agentkit import (
18
13
  AgentKitConfig,
19
14
  CdpEvmWalletProvider,
20
15
  )
21
- from langchain.tools import StructuredTool
22
- from langchain_core.tools import BaseTool
16
+ from langchain_core.tools import BaseTool, StructuredTool
23
17
  from langchain_core.tools.base import ToolException
24
18
  from langgraph.runtime import get_runtime
25
19
  from pydantic import (
@@ -27,18 +21,19 @@ from pydantic import (
27
21
  )
28
22
  from pydantic.v1 import ValidationError as ValidationErrorV1
29
23
  from redis.exceptions import RedisError
30
- from web3 import Web3
31
24
 
32
25
  from intentkit.abstracts.graph import AgentContext
33
- from intentkit.abstracts.skill import SkillStoreABC
34
26
  from intentkit.clients import get_wallet_provider
35
- from intentkit.clients.web3 import get_web3_client
27
+ from intentkit.models.agent import Agent
36
28
  from intentkit.models.redis import get_redis
29
+ from intentkit.models.skill import (
30
+ AgentSkillData,
31
+ AgentSkillDataCreate,
32
+ ChatSkillData,
33
+ ChatSkillDataCreate,
34
+ )
37
35
  from intentkit.utils.error import IntentKitAPIError, RateLimitExceeded
38
36
 
39
- if TYPE_CHECKING:
40
- from intentkit.models.agent import Agent
41
-
42
37
  SkillState = Literal["disabled", "public", "private"]
43
38
  SkillOwnerState = Literal["disabled", "private"]
44
39
  APIKeyProviderValue = Literal["platform", "agent_owner"]
@@ -48,9 +43,9 @@ class SkillConfig(TypedDict):
48
43
  """Abstract base class for skill configuration."""
49
44
 
50
45
  enabled: bool
51
- states: Dict[str, SkillState | SkillOwnerState]
46
+ states: dict[str, SkillState | SkillOwnerState]
52
47
  api_key_provider: NotRequired[APIKeyProviderValue]
53
- __extra__: NotRequired[Dict[str, Any]]
48
+ __extra__: NotRequired[dict[str, Any]]
54
49
 
55
50
 
56
51
  class IntentKitSkill(BaseTool):
@@ -58,17 +53,16 @@ class IntentKitSkill(BaseTool):
58
53
  Will have predefined abilities.
59
54
  """
60
55
 
61
- skill_store: SkillStoreABC
62
56
  # overwrite the value of BaseTool
63
- handle_tool_error: Optional[Union[bool, str, Callable[[ToolException], str]]] = (
57
+ handle_tool_error: bool | str | Callable[[ToolException], str] | None = (
64
58
  lambda e: f"tool error: {e}"
65
59
  )
66
60
  """Handle the content of the ToolException thrown."""
67
61
 
68
62
  # overwrite the value of BaseTool
69
- handle_validation_error: Optional[
70
- Union[bool, str, Callable[[Union[ValidationError, ValidationErrorV1]], str]]
71
- ] = lambda e: f"validation error: {e}"
63
+ handle_validation_error: (
64
+ bool | str | Callable[[ValidationError | ValidationErrorV1], str] | None
65
+ ) = lambda e: f"validation error: {e}"
72
66
  """Handle the content of the ValidationError thrown."""
73
67
 
74
68
  # Logger for the class
@@ -79,15 +73,12 @@ class IntentKitSkill(BaseTool):
79
73
  """Get the category of the skill."""
80
74
  raise NotImplementedError
81
75
 
82
- async def user_rate_limit(
83
- self, user_id: str, limit: int, minutes: int, key: str
84
- ) -> None:
76
+ async def user_rate_limit(self, limit: int, seconds: int, key: str) -> None:
85
77
  """Check if a user has exceeded the rate limit for this skill.
86
78
 
87
79
  Args:
88
- user_id: The ID of the user to check
89
80
  limit: Maximum number of requests allowed
90
- minutes: Time window in minutes
81
+ seconds: Time window in seconds
91
82
  key: The key to use for rate limiting (e.g., skill name or category)
92
83
 
93
84
  Raises:
@@ -96,25 +87,48 @@ class IntentKitSkill(BaseTool):
96
87
  Returns:
97
88
  None: Always returns None if no exception is raised
98
89
  """
99
- if not user_id:
100
- return None # No rate limiting for users without ID
90
+ try:
91
+ context = self.get_context()
92
+ except ValueError:
93
+ self.logger.info(
94
+ "AgentContext not available, skipping rate limit for %s",
95
+ key,
96
+ )
97
+ return None
98
+
99
+ user_identifier = context.user_id or context.agent_id
100
+ if not user_identifier:
101
+ return None # No rate limiting when no identifier is available
102
+
103
+ try:
104
+ max_requests = int(limit)
105
+ window_seconds = int(seconds)
106
+ except (TypeError, ValueError):
107
+ self.logger.info(
108
+ "Invalid user rate limit parameters for %s: limit=%r, seconds=%r",
109
+ key,
110
+ limit,
111
+ seconds,
112
+ )
113
+ return None
114
+
115
+ if window_seconds <= 0 or max_requests <= 0:
116
+ return None
101
117
 
102
118
  try:
103
119
  redis = get_redis()
104
120
  # Create a unique key for this rate limit and user
105
- rate_limit_key = f"rate_limit:{key}:{user_id}"
121
+ rate_limit_key = f"rate_limit:{key}:{user_identifier}"
106
122
 
107
123
  # Get the current count
108
124
  count = await redis.incr(rate_limit_key)
109
125
 
110
126
  # Set expiration if this is the first request
111
127
  if count == 1:
112
- await redis.expire(
113
- rate_limit_key, minutes * 60
114
- ) # Convert minutes to seconds
128
+ await redis.expire(rate_limit_key, window_seconds)
115
129
 
116
130
  # Check if user has exceeded the limit
117
- if count > limit:
131
+ if count > max_requests:
118
132
  raise RateLimitExceeded(f"Rate limit exceeded for {key}")
119
133
 
120
134
  return None
@@ -130,40 +144,97 @@ class IntentKitSkill(BaseTool):
130
144
  )
131
145
  return None
132
146
 
133
- async def user_rate_limit_by_skill(
134
- self, user_id: str, limit: int, minutes: int
135
- ) -> None:
147
+ async def user_rate_limit_by_skill(self, limit: int, seconds: int) -> None:
136
148
  """Check if a user has exceeded the rate limit for this specific skill.
137
149
 
138
150
  This uses the skill name as the rate limit key.
139
151
 
140
152
  Args:
141
- user_id: The ID of the user to check
142
153
  limit: Maximum number of requests allowed
143
- minutes: Time window in minutes
154
+ seconds: Time window in seconds
144
155
 
145
156
  Raises:
146
157
  RateLimitExceeded: If the user has exceeded the rate limit
147
158
  """
148
- return await self.user_rate_limit(user_id, limit, minutes, self.name)
159
+ return await self.user_rate_limit(limit, seconds, self.name)
149
160
 
150
- async def user_rate_limit_by_category(
151
- self, user_id: str, limit: int, minutes: int
152
- ) -> None:
161
+ async def user_rate_limit_by_category(self, limit: int, seconds: int) -> None:
153
162
  """Check if a user has exceeded the rate limit for this skill category.
154
163
 
155
164
  This uses the skill category as the rate limit key, which means the limit
156
165
  is shared across all skills in the same category.
157
166
 
158
167
  Args:
159
- user_id: The ID of the user to check
160
168
  limit: Maximum number of requests allowed
161
- minutes: Time window in minutes
169
+ seconds: Time window in seconds
162
170
 
163
171
  Raises:
164
172
  RateLimitExceeded: If the user has exceeded the rate limit
165
173
  """
166
- return await self.user_rate_limit(user_id, limit, minutes, self.category)
174
+ return await self.user_rate_limit(limit, seconds, self.category)
175
+
176
+ async def global_rate_limit(self, limit: int, seconds: int, key: str) -> None:
177
+ """Check if a global rate limit has been exceeded for a given key.
178
+
179
+ Args:
180
+ limit: Maximum number of requests allowed
181
+ seconds: Time window in seconds
182
+ key: The key to use for rate limiting (e.g., skill name or category)
183
+
184
+ Raises:
185
+ RateLimitExceeded: If the global limit has been exceeded
186
+
187
+ Returns:
188
+ None: Always returns None if no exception is raised
189
+ """
190
+ try:
191
+ max_requests = int(limit)
192
+ window_seconds = int(seconds)
193
+ except (TypeError, ValueError):
194
+ self.logger.info(
195
+ "Invalid global rate limit parameters for %s: limit=%r, seconds=%r",
196
+ key,
197
+ limit,
198
+ seconds,
199
+ )
200
+ return None
201
+
202
+ if window_seconds <= 0 or max_requests <= 0:
203
+ return None
204
+
205
+ try:
206
+ redis = get_redis()
207
+ rate_limit_key = f"rate_limit:{key}"
208
+
209
+ count = await redis.incr(rate_limit_key)
210
+
211
+ if count == 1:
212
+ await redis.expire(rate_limit_key, window_seconds)
213
+
214
+ if count > max_requests:
215
+ raise RateLimitExceeded(f"Global rate limit exceeded for {key}")
216
+
217
+ return None
218
+
219
+ except RuntimeError:
220
+ self.logger.info(
221
+ "Redis not initialized, skipping global rate limit for %s",
222
+ key,
223
+ )
224
+ return None
225
+ except RedisError as e:
226
+ self.logger.info(
227
+ f"Redis error in global rate limiting: {e}, skipping rate limit for {key}"
228
+ )
229
+ return None
230
+
231
+ async def global_rate_limit_by_skill(self, limit: int, seconds: int) -> None:
232
+ """Apply a global rate limit scoped to this specific skill."""
233
+ return await self.global_rate_limit(limit, seconds, self.name)
234
+
235
+ async def global_rate_limit_by_category(self, limit: int, seconds: int) -> None:
236
+ """Apply a global rate limit scoped to this skill category."""
237
+ return await self.global_rate_limit(limit, seconds, self.category)
167
238
 
168
239
  def _run(self, *args: Any, **kwargs: Any) -> Any:
169
240
  raise NotImplementedError(
@@ -177,21 +248,73 @@ class IntentKitSkill(BaseTool):
177
248
  raise ValueError("No AgentContext found")
178
249
  return runtime.context
179
250
 
180
- def web3_client(self) -> Web3:
181
- """Get a Web3 client for the skill."""
251
+ async def get_agent_skill_data(
252
+ self,
253
+ key: str,
254
+ ) -> dict[str, Any] | None:
255
+ """Retrieve persisted data for this skill scoped to the active agent."""
256
+ return await self.get_agent_skill_data_raw(self.name, key)
257
+
258
+ async def get_agent_skill_data_raw(
259
+ self,
260
+ skill_name: str,
261
+ key: str,
262
+ ) -> dict[str, Any] | None:
263
+ """Retrieve persisted data for a specific skill scoped to the active agent."""
182
264
  context = self.get_context()
183
- agent = context.agent
184
- network_id = agent.network_id
265
+ return await AgentSkillData.get(context.agent_id, skill_name, key)
266
+
267
+ async def save_agent_skill_data(self, key: str, data: dict[str, Any]) -> None:
268
+ """Persist data for this skill scoped to the active agent."""
269
+ await self.save_agent_skill_data_raw(self.name, key, data)
270
+
271
+ async def save_agent_skill_data_raw(
272
+ self,
273
+ skill_name: str,
274
+ key: str,
275
+ data: dict[str, Any],
276
+ ) -> None:
277
+ """Persist data for a specific skill scoped to the active agent."""
278
+ context = self.get_context()
279
+ skill_data = AgentSkillDataCreate(
280
+ agent_id=context.agent_id,
281
+ skill=skill_name,
282
+ key=key,
283
+ data=data,
284
+ )
285
+ await skill_data.save()
286
+
287
+ async def delete_agent_skill_data(self, key: str) -> None:
288
+ """Remove persisted data for this skill scoped to the active agent."""
289
+ context = self.get_context()
290
+ await AgentSkillData.delete(context.agent_id, self.name, key)
185
291
 
186
- return get_web3_client(network_id)
292
+ async def get_thread_skill_data(
293
+ self,
294
+ key: str,
295
+ ) -> dict[str, Any] | None:
296
+ """Retrieve persisted data for this skill scoped to the active chat."""
297
+ context = self.get_context()
298
+ return await ChatSkillData.get(context.chat_id, self.name, key)
299
+
300
+ async def save_thread_skill_data(self, key: str, data: dict[str, Any]) -> None:
301
+ """Persist data for this skill scoped to the active chat."""
302
+ context = self.get_context()
303
+ skill_data = ChatSkillDataCreate(
304
+ chat_id=context.chat_id,
305
+ agent_id=context.agent_id,
306
+ skill=self.name,
307
+ key=key,
308
+ data=data,
309
+ )
310
+ await skill_data.save()
187
311
 
188
312
 
189
313
  async def get_agentkit_actions(
190
314
  agent_id: str,
191
- _store: SkillStoreABC,
192
315
  provider_factories: Sequence[Callable[[], object]],
193
316
  *,
194
- agent: Optional["Agent"] = None,
317
+ agent: Agent | None = None,
195
318
  ) -> list[Action]:
196
319
  """Build an AgentKit instance and return its actions."""
197
320
 
@@ -1,10 +1,10 @@
1
1
  """Basename AgentKit skills."""
2
2
 
3
- from typing import TYPE_CHECKING, Optional, TypedDict
3
+ from typing import TypedDict
4
4
 
5
5
  from coinbase_agentkit import basename_action_provider
6
6
 
7
- from intentkit.abstracts.skill import SkillStoreABC
7
+ from intentkit.models.agent import Agent
8
8
  from intentkit.skills.base import (
9
9
  SkillConfig,
10
10
  SkillState,
@@ -13,9 +13,6 @@ from intentkit.skills.base import (
13
13
  )
14
14
  from intentkit.skills.basename.base import BasenameBaseTool
15
15
 
16
- if TYPE_CHECKING:
17
- from intentkit.models.agent import Agent
18
-
19
16
 
20
17
  class SkillStates(TypedDict):
21
18
  BasenameActionProvider_register_basename: SkillState
@@ -30,9 +27,8 @@ class Config(SkillConfig):
30
27
  async def get_skills(
31
28
  config: "Config",
32
29
  is_private: bool,
33
- store: SkillStoreABC,
34
30
  agent_id: str,
35
- agent: Optional["Agent"] = None,
31
+ agent: Agent | None = None,
36
32
  **_,
37
33
  ) -> list[BasenameBaseTool]:
38
34
  """Get all Basename skills."""
@@ -45,7 +41,7 @@ async def get_skills(
45
41
  available_skills.append(skill_name)
46
42
 
47
43
  actions = await get_agentkit_actions(
48
- agent_id, store, [basename_action_provider], agent=agent
44
+ agent_id, [basename_action_provider], agent=agent
49
45
  )
50
46
  tools: list[BasenameBaseTool] = []
51
47
  for skill in available_skills: