intentkit 0.7.5.dev3__py3-none-any.whl → 0.8.34.dev7__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.
Files changed (393) hide show
  1. intentkit/MANIFEST.in +14 -0
  2. intentkit/README.md +88 -0
  3. intentkit/__init__.py +6 -4
  4. intentkit/abstracts/agent.py +4 -5
  5. intentkit/abstracts/engine.py +5 -5
  6. intentkit/abstracts/graph.py +15 -8
  7. intentkit/abstracts/skill.py +6 -144
  8. intentkit/abstracts/twitter.py +4 -5
  9. intentkit/clients/__init__.py +9 -2
  10. intentkit/clients/cdp.py +129 -153
  11. intentkit/{utils → clients}/s3.py +109 -34
  12. intentkit/clients/twitter.py +83 -62
  13. intentkit/clients/web3.py +4 -7
  14. intentkit/config/config.py +123 -90
  15. intentkit/core/account_checking.py +802 -0
  16. intentkit/core/agent.py +313 -498
  17. intentkit/core/asset.py +267 -0
  18. intentkit/core/chat.py +5 -3
  19. intentkit/core/client.py +1 -1
  20. intentkit/core/credit.py +49 -41
  21. intentkit/core/draft.py +201 -0
  22. intentkit/core/draft_chat.py +118 -0
  23. intentkit/core/engine.py +378 -287
  24. intentkit/core/manager/__init__.py +25 -0
  25. intentkit/core/manager/engine.py +220 -0
  26. intentkit/core/manager/service.py +172 -0
  27. intentkit/core/manager/skills.py +178 -0
  28. intentkit/core/middleware.py +231 -0
  29. intentkit/core/prompt.py +74 -114
  30. intentkit/core/scheduler.py +143 -0
  31. intentkit/core/statistics.py +168 -0
  32. intentkit/models/agent.py +931 -518
  33. intentkit/models/agent_data.py +165 -106
  34. intentkit/models/agent_schema.json +38 -251
  35. intentkit/models/app_setting.py +15 -13
  36. intentkit/models/chat.py +86 -140
  37. intentkit/models/credit.py +182 -162
  38. intentkit/models/db.py +42 -23
  39. intentkit/models/db_mig.py +120 -3
  40. intentkit/models/draft.py +222 -0
  41. intentkit/models/llm.csv +31 -0
  42. intentkit/models/llm.py +262 -370
  43. intentkit/models/redis.py +6 -4
  44. intentkit/models/skill.py +222 -101
  45. intentkit/models/skills.csv +173 -0
  46. intentkit/models/team.py +189 -0
  47. intentkit/models/user.py +103 -31
  48. intentkit/skills/acolyt/__init__.py +2 -9
  49. intentkit/skills/acolyt/ask.py +3 -4
  50. intentkit/skills/acolyt/base.py +4 -9
  51. intentkit/skills/acolyt/schema.json +4 -3
  52. intentkit/skills/aixbt/__init__.py +2 -13
  53. intentkit/skills/aixbt/base.py +1 -7
  54. intentkit/skills/aixbt/projects.py +14 -15
  55. intentkit/skills/aixbt/schema.json +4 -4
  56. intentkit/skills/allora/__init__.py +2 -9
  57. intentkit/skills/allora/base.py +4 -9
  58. intentkit/skills/allora/price.py +3 -4
  59. intentkit/skills/allora/schema.json +3 -2
  60. intentkit/skills/base.py +241 -41
  61. intentkit/skills/basename/__init__.py +51 -0
  62. intentkit/skills/basename/base.py +11 -0
  63. intentkit/skills/basename/basename.svg +11 -0
  64. intentkit/skills/basename/schema.json +58 -0
  65. intentkit/skills/carv/__init__.py +115 -121
  66. intentkit/skills/carv/base.py +184 -185
  67. intentkit/skills/carv/fetch_news.py +3 -3
  68. intentkit/skills/carv/onchain_query.py +4 -4
  69. intentkit/skills/carv/schema.json +134 -137
  70. intentkit/skills/carv/token_info_and_price.py +6 -6
  71. intentkit/skills/casino/__init__.py +4 -15
  72. intentkit/skills/casino/base.py +1 -7
  73. intentkit/skills/casino/deck_draw.py +5 -8
  74. intentkit/skills/casino/deck_shuffle.py +6 -6
  75. intentkit/skills/casino/dice_roll.py +2 -4
  76. intentkit/skills/casino/schema.json +0 -1
  77. intentkit/skills/cdp/__init__.py +22 -84
  78. intentkit/skills/cdp/base.py +1 -7
  79. intentkit/skills/cdp/schema.json +11 -314
  80. intentkit/skills/chainlist/__init__.py +2 -7
  81. intentkit/skills/chainlist/base.py +1 -7
  82. intentkit/skills/chainlist/chain_lookup.py +18 -18
  83. intentkit/skills/chainlist/schema.json +3 -5
  84. intentkit/skills/common/__init__.py +2 -9
  85. intentkit/skills/common/base.py +1 -7
  86. intentkit/skills/common/current_time.py +1 -2
  87. intentkit/skills/common/schema.json +2 -2
  88. intentkit/skills/cookiefun/__init__.py +6 -9
  89. intentkit/skills/cookiefun/base.py +2 -7
  90. intentkit/skills/cookiefun/get_account_details.py +7 -7
  91. intentkit/skills/cookiefun/get_account_feed.py +19 -19
  92. intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
  93. intentkit/skills/cookiefun/get_sectors.py +3 -3
  94. intentkit/skills/cookiefun/schema.json +1 -3
  95. intentkit/skills/cookiefun/search_accounts.py +9 -9
  96. intentkit/skills/cryptocompare/__init__.py +7 -24
  97. intentkit/skills/cryptocompare/api.py +2 -3
  98. intentkit/skills/cryptocompare/base.py +10 -24
  99. intentkit/skills/cryptocompare/fetch_news.py +4 -5
  100. intentkit/skills/cryptocompare/fetch_price.py +6 -7
  101. intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
  102. intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
  103. intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
  104. intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
  105. intentkit/skills/cryptocompare/schema.json +3 -3
  106. intentkit/skills/cryptopanic/__init__.py +7 -10
  107. intentkit/skills/cryptopanic/base.py +51 -55
  108. intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
  109. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
  110. intentkit/skills/cryptopanic/schema.json +105 -103
  111. intentkit/skills/dapplooker/__init__.py +2 -9
  112. intentkit/skills/dapplooker/base.py +4 -9
  113. intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
  114. intentkit/skills/dapplooker/schema.json +3 -5
  115. intentkit/skills/defillama/__init__.py +24 -74
  116. intentkit/skills/defillama/api.py +6 -9
  117. intentkit/skills/defillama/base.py +8 -19
  118. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
  119. intentkit/skills/defillama/coins/fetch_block.py +6 -8
  120. intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
  121. intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
  122. intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
  123. intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
  124. intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
  125. intentkit/skills/defillama/config/chains.py +1 -3
  126. intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
  127. intentkit/skills/defillama/schema.json +5 -1
  128. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
  129. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
  130. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
  131. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
  132. intentkit/skills/defillama/tests/api_integration.test.py +1 -1
  133. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
  134. intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
  135. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
  136. intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
  137. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
  138. intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
  139. intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
  140. intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
  141. intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
  142. intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
  143. intentkit/skills/defillama/yields/fetch_pools.py +26 -30
  144. intentkit/skills/dexscreener/__init__.py +97 -102
  145. intentkit/skills/dexscreener/base.py +125 -130
  146. intentkit/skills/dexscreener/get_pair_info.py +4 -5
  147. intentkit/skills/dexscreener/get_token_pairs.py +4 -5
  148. intentkit/skills/dexscreener/get_tokens_info.py +7 -8
  149. intentkit/skills/dexscreener/model/search_token_response.py +80 -82
  150. intentkit/skills/dexscreener/schema.json +91 -93
  151. intentkit/skills/dexscreener/search_token.py +182 -184
  152. intentkit/skills/dexscreener/utils.py +15 -14
  153. intentkit/skills/dune_analytics/__init__.py +7 -9
  154. intentkit/skills/dune_analytics/base.py +48 -52
  155. intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
  156. intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
  157. intentkit/skills/dune_analytics/schema.json +104 -99
  158. intentkit/skills/elfa/__init__.py +5 -18
  159. intentkit/skills/elfa/base.py +10 -14
  160. intentkit/skills/elfa/mention.py +19 -21
  161. intentkit/skills/elfa/schema.json +3 -2
  162. intentkit/skills/elfa/stats.py +4 -4
  163. intentkit/skills/elfa/tokens.py +12 -12
  164. intentkit/skills/elfa/utils.py +26 -28
  165. intentkit/skills/enso/__init__.py +11 -31
  166. intentkit/skills/enso/base.py +54 -35
  167. intentkit/skills/enso/best_yield.py +16 -24
  168. intentkit/skills/enso/networks.py +6 -11
  169. intentkit/skills/enso/prices.py +11 -13
  170. intentkit/skills/enso/route.py +34 -38
  171. intentkit/skills/enso/schema.json +3 -2
  172. intentkit/skills/enso/tokens.py +29 -38
  173. intentkit/skills/enso/wallet.py +76 -191
  174. intentkit/skills/erc20/__init__.py +50 -0
  175. intentkit/skills/erc20/base.py +11 -0
  176. intentkit/skills/erc20/erc20.svg +5 -0
  177. intentkit/skills/erc20/schema.json +74 -0
  178. intentkit/skills/erc721/__init__.py +53 -0
  179. intentkit/skills/erc721/base.py +11 -0
  180. intentkit/skills/erc721/erc721.svg +5 -0
  181. intentkit/skills/erc721/schema.json +90 -0
  182. intentkit/skills/firecrawl/__init__.py +5 -18
  183. intentkit/skills/firecrawl/base.py +4 -9
  184. intentkit/skills/firecrawl/clear.py +4 -8
  185. intentkit/skills/firecrawl/crawl.py +19 -19
  186. intentkit/skills/firecrawl/query.py +4 -3
  187. intentkit/skills/firecrawl/schema.json +2 -6
  188. intentkit/skills/firecrawl/scrape.py +17 -22
  189. intentkit/skills/firecrawl/utils.py +50 -42
  190. intentkit/skills/github/__init__.py +2 -7
  191. intentkit/skills/github/base.py +1 -7
  192. intentkit/skills/github/github_search.py +1 -2
  193. intentkit/skills/github/schema.json +3 -4
  194. intentkit/skills/heurist/__init__.py +8 -27
  195. intentkit/skills/heurist/base.py +4 -9
  196. intentkit/skills/heurist/image_generation_animagine_xl.py +13 -15
  197. intentkit/skills/heurist/image_generation_arthemy_comics.py +13 -15
  198. intentkit/skills/heurist/image_generation_arthemy_real.py +13 -15
  199. intentkit/skills/heurist/image_generation_braindance.py +13 -15
  200. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +13 -15
  201. intentkit/skills/heurist/image_generation_flux_1_dev.py +13 -15
  202. intentkit/skills/heurist/image_generation_sdxl.py +13 -15
  203. intentkit/skills/heurist/schema.json +2 -2
  204. intentkit/skills/http/__init__.py +4 -15
  205. intentkit/skills/http/base.py +1 -7
  206. intentkit/skills/http/get.py +21 -16
  207. intentkit/skills/http/post.py +23 -18
  208. intentkit/skills/http/put.py +23 -18
  209. intentkit/skills/http/schema.json +4 -5
  210. intentkit/skills/lifi/__init__.py +8 -13
  211. intentkit/skills/lifi/base.py +3 -9
  212. intentkit/skills/lifi/schema.json +17 -8
  213. intentkit/skills/lifi/token_execute.py +150 -60
  214. intentkit/skills/lifi/token_quote.py +8 -10
  215. intentkit/skills/lifi/utils.py +104 -51
  216. intentkit/skills/moralis/__init__.py +6 -10
  217. intentkit/skills/moralis/api.py +6 -7
  218. intentkit/skills/moralis/base.py +5 -10
  219. intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
  220. intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
  221. intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
  222. intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
  223. intentkit/skills/moralis/schema.json +7 -2
  224. intentkit/skills/morpho/__init__.py +52 -0
  225. intentkit/skills/morpho/base.py +11 -0
  226. intentkit/skills/morpho/morpho.svg +12 -0
  227. intentkit/skills/morpho/schema.json +73 -0
  228. intentkit/skills/nation/__init__.py +4 -9
  229. intentkit/skills/nation/base.py +5 -10
  230. intentkit/skills/nation/nft_check.py +3 -4
  231. intentkit/skills/nation/schema.json +4 -3
  232. intentkit/skills/onchain.py +30 -0
  233. intentkit/skills/openai/__init__.py +17 -18
  234. intentkit/skills/openai/base.py +10 -14
  235. intentkit/skills/openai/dalle_image_generation.py +4 -9
  236. intentkit/skills/openai/gpt_avatar_generator.py +102 -0
  237. intentkit/skills/openai/gpt_image_generation.py +5 -9
  238. intentkit/skills/openai/gpt_image_mini_generator.py +92 -0
  239. intentkit/skills/openai/gpt_image_to_image.py +5 -9
  240. intentkit/skills/openai/image_to_text.py +3 -7
  241. intentkit/skills/openai/schema.json +34 -3
  242. intentkit/skills/portfolio/__init__.py +11 -35
  243. intentkit/skills/portfolio/base.py +33 -19
  244. intentkit/skills/portfolio/schema.json +3 -5
  245. intentkit/skills/portfolio/token_balances.py +21 -21
  246. intentkit/skills/portfolio/wallet_approvals.py +17 -18
  247. intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
  248. intentkit/skills/portfolio/wallet_history.py +31 -31
  249. intentkit/skills/portfolio/wallet_net_worth.py +13 -13
  250. intentkit/skills/portfolio/wallet_nfts.py +19 -19
  251. intentkit/skills/portfolio/wallet_profitability.py +18 -18
  252. intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
  253. intentkit/skills/portfolio/wallet_stats.py +3 -3
  254. intentkit/skills/portfolio/wallet_swaps.py +19 -19
  255. intentkit/skills/pyth/__init__.py +50 -0
  256. intentkit/skills/pyth/base.py +11 -0
  257. intentkit/skills/pyth/pyth.svg +6 -0
  258. intentkit/skills/pyth/schema.json +75 -0
  259. intentkit/skills/skills.toml +36 -0
  260. intentkit/skills/slack/__init__.py +5 -17
  261. intentkit/skills/slack/base.py +3 -9
  262. intentkit/skills/slack/get_channel.py +8 -8
  263. intentkit/skills/slack/get_message.py +9 -9
  264. intentkit/skills/slack/schedule_message.py +5 -5
  265. intentkit/skills/slack/schema.json +2 -2
  266. intentkit/skills/slack/send_message.py +3 -5
  267. intentkit/skills/supabase/__init__.py +7 -23
  268. intentkit/skills/supabase/base.py +1 -7
  269. intentkit/skills/supabase/delete_data.py +4 -4
  270. intentkit/skills/supabase/fetch_data.py +12 -12
  271. intentkit/skills/supabase/insert_data.py +4 -4
  272. intentkit/skills/supabase/invoke_function.py +6 -6
  273. intentkit/skills/supabase/schema.json +2 -3
  274. intentkit/skills/supabase/update_data.py +6 -6
  275. intentkit/skills/supabase/upsert_data.py +4 -4
  276. intentkit/skills/superfluid/__init__.py +53 -0
  277. intentkit/skills/superfluid/base.py +11 -0
  278. intentkit/skills/superfluid/schema.json +89 -0
  279. intentkit/skills/superfluid/superfluid.svg +6 -0
  280. intentkit/skills/system/__init__.py +7 -24
  281. intentkit/skills/system/add_autonomous_task.py +10 -12
  282. intentkit/skills/system/delete_autonomous_task.py +2 -2
  283. intentkit/skills/system/edit_autonomous_task.py +14 -18
  284. intentkit/skills/system/list_autonomous_tasks.py +3 -5
  285. intentkit/skills/system/read_agent_api_key.py +6 -4
  286. intentkit/skills/system/regenerate_agent_api_key.py +6 -4
  287. intentkit/skills/system/schema.json +6 -8
  288. intentkit/skills/tavily/__init__.py +3 -12
  289. intentkit/skills/tavily/base.py +4 -9
  290. intentkit/skills/tavily/schema.json +3 -5
  291. intentkit/skills/tavily/tavily_extract.py +2 -4
  292. intentkit/skills/tavily/tavily_search.py +4 -6
  293. intentkit/skills/token/__init__.py +5 -10
  294. intentkit/skills/token/base.py +7 -11
  295. intentkit/skills/token/erc20_transfers.py +19 -19
  296. intentkit/skills/token/schema.json +3 -6
  297. intentkit/skills/token/token_analytics.py +3 -3
  298. intentkit/skills/token/token_price.py +13 -13
  299. intentkit/skills/token/token_search.py +9 -9
  300. intentkit/skills/twitter/__init__.py +11 -35
  301. intentkit/skills/twitter/base.py +22 -34
  302. intentkit/skills/twitter/follow_user.py +2 -6
  303. intentkit/skills/twitter/get_mentions.py +5 -12
  304. intentkit/skills/twitter/get_timeline.py +4 -12
  305. intentkit/skills/twitter/get_user_by_username.py +2 -6
  306. intentkit/skills/twitter/get_user_tweets.py +5 -13
  307. intentkit/skills/twitter/like_tweet.py +2 -6
  308. intentkit/skills/twitter/post_tweet.py +6 -9
  309. intentkit/skills/twitter/reply_tweet.py +6 -9
  310. intentkit/skills/twitter/retweet.py +2 -6
  311. intentkit/skills/twitter/schema.json +1 -0
  312. intentkit/skills/twitter/search_tweets.py +4 -12
  313. intentkit/skills/unrealspeech/__init__.py +2 -7
  314. intentkit/skills/unrealspeech/base.py +2 -8
  315. intentkit/skills/unrealspeech/schema.json +2 -5
  316. intentkit/skills/unrealspeech/text_to_speech.py +8 -8
  317. intentkit/skills/venice_audio/__init__.py +98 -106
  318. intentkit/skills/venice_audio/base.py +117 -121
  319. intentkit/skills/venice_audio/input.py +41 -41
  320. intentkit/skills/venice_audio/schema.json +151 -152
  321. intentkit/skills/venice_audio/venice_audio.py +38 -21
  322. intentkit/skills/venice_image/__init__.py +147 -154
  323. intentkit/skills/venice_image/api.py +138 -138
  324. intentkit/skills/venice_image/base.py +185 -192
  325. intentkit/skills/venice_image/config.py +33 -35
  326. intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
  327. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
  328. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
  329. intentkit/skills/venice_image/image_generation/image_generation_base.py +11 -10
  330. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
  331. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
  332. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
  333. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
  334. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
  335. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
  336. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
  337. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
  338. intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
  339. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
  340. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
  341. intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
  342. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
  343. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
  344. intentkit/skills/venice_image/schema.json +267 -267
  345. intentkit/skills/venice_image/utils.py +77 -78
  346. intentkit/skills/web_scraper/__init__.py +5 -18
  347. intentkit/skills/web_scraper/base.py +21 -7
  348. intentkit/skills/web_scraper/document_indexer.py +7 -6
  349. intentkit/skills/web_scraper/schema.json +2 -6
  350. intentkit/skills/web_scraper/scrape_and_index.py +15 -15
  351. intentkit/skills/web_scraper/utils.py +62 -63
  352. intentkit/skills/web_scraper/website_indexer.py +17 -19
  353. intentkit/skills/weth/__init__.py +49 -0
  354. intentkit/skills/weth/base.py +11 -0
  355. intentkit/skills/weth/schema.json +58 -0
  356. intentkit/skills/weth/weth.svg +6 -0
  357. intentkit/skills/wow/__init__.py +51 -0
  358. intentkit/skills/wow/base.py +11 -0
  359. intentkit/skills/wow/schema.json +89 -0
  360. intentkit/skills/wow/wow.svg +7 -0
  361. intentkit/skills/x402/__init__.py +58 -0
  362. intentkit/skills/x402/base.py +99 -0
  363. intentkit/skills/x402/http_request.py +117 -0
  364. intentkit/skills/x402/schema.json +40 -0
  365. intentkit/skills/x402/x402.webp +0 -0
  366. intentkit/skills/xmtp/__init__.py +4 -15
  367. intentkit/skills/xmtp/base.py +5 -5
  368. intentkit/skills/xmtp/price.py +7 -6
  369. intentkit/skills/xmtp/schema.json +69 -71
  370. intentkit/skills/xmtp/swap.py +6 -8
  371. intentkit/skills/xmtp/transfer.py +4 -6
  372. intentkit/utils/__init__.py +4 -0
  373. intentkit/utils/chain.py +198 -96
  374. intentkit/utils/ens.py +135 -0
  375. intentkit/utils/error.py +5 -2
  376. intentkit/utils/logging.py +9 -11
  377. intentkit/utils/schema.py +100 -0
  378. intentkit/utils/slack_alert.py +8 -8
  379. intentkit/utils/tx.py +16 -8
  380. intentkit/uv.lock +3377 -0
  381. {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/METADATA +13 -15
  382. intentkit-0.8.34.dev7.dist-info/RECORD +478 -0
  383. intentkit-0.8.34.dev7.dist-info/licenses/LICENSE +21 -0
  384. intentkit/core/node.py +0 -215
  385. intentkit/models/conversation.py +0 -286
  386. intentkit/models/generator.py +0 -347
  387. intentkit/skills/cdp/get_balance.py +0 -110
  388. intentkit/skills/cdp/swap.py +0 -121
  389. intentkit/skills/moralis/tests/__init__.py +0 -0
  390. intentkit/skills/moralis/tests/test_wallet.py +0 -511
  391. intentkit-0.7.5.dev3.dist-info/RECORD +0 -424
  392. {intentkit-0.7.5.dev3.dist-info/licenses → intentkit}/LICENSE +0 -0
  393. {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/WHEEL +0 -0
@@ -1,7 +1,5 @@
1
1
  """Tool for fetching pool data via DeFi Llama API."""
2
2
 
3
- from typing import Optional
4
-
5
3
  from pydantic import BaseModel, Field
6
4
 
7
5
  from intentkit.skills.defillama.api import fetch_pools
@@ -21,13 +19,13 @@ Returns data including:
21
19
  class PredictionData(BaseModel):
22
20
  """Model representing prediction data for a pool."""
23
21
 
24
- predictedClass: Optional[str] = Field(
22
+ predictedClass: str | None = Field(
25
23
  None, description="Predicted direction of APY movement"
26
24
  )
27
- predictedProbability: Optional[float] = Field(
25
+ predictedProbability: float | None = Field(
28
26
  None, description="Probability of the prediction"
29
27
  )
30
- binnedConfidence: Optional[int] = Field(None, description="Confidence level bucket")
28
+ binnedConfidence: int | None = Field(None, description="Confidence level bucket")
31
29
 
32
30
 
33
31
  class PoolData(BaseModel):
@@ -37,38 +35,36 @@ class PoolData(BaseModel):
37
35
  project: str = Field(..., description="Protocol or project name")
38
36
  symbol: str = Field(..., description="Token or pool symbol")
39
37
  tvlUsd: float = Field(..., description="Total Value Locked in USD")
40
- apyBase: Optional[float] = Field(None, description="Base APY without rewards")
41
- apyReward: Optional[float] = Field(None, description="Additional APY from rewards")
42
- apy: Optional[float] = Field(None, description="Total APY including rewards")
43
- rewardTokens: Optional[list[str]] = Field(
38
+ apyBase: float | None = Field(None, description="Base APY without rewards")
39
+ apyReward: float | None = Field(None, description="Additional APY from rewards")
40
+ apy: float | None = Field(None, description="Total APY including rewards")
41
+ rewardTokens: list[str] | None = Field(
44
42
  None, description="List of reward token addresses"
45
43
  )
46
- pool: Optional[str] = Field(None, description="Pool identifier")
47
- apyPct1D: Optional[float] = Field(None, description="1-day APY percentage change")
48
- apyPct7D: Optional[float] = Field(None, description="7-day APY percentage change")
49
- apyPct30D: Optional[float] = Field(None, description="30-day APY percentage change")
44
+ pool: str | None = Field(None, description="Pool identifier")
45
+ apyPct1D: float | None = Field(None, description="1-day APY percentage change")
46
+ apyPct7D: float | None = Field(None, description="7-day APY percentage change")
47
+ apyPct30D: float | None = Field(None, description="30-day APY percentage change")
50
48
  stablecoin: bool = Field(False, description="Whether pool involves stablecoins")
51
49
  ilRisk: str = Field("no", description="Impermanent loss risk assessment")
52
50
  exposure: str = Field("single", description="Asset exposure type")
53
- predictions: Optional[PredictionData] = Field(
51
+ predictions: PredictionData | None = Field(
54
52
  None, description="APY movement predictions"
55
53
  )
56
- poolMeta: Optional[str] = Field(None, description="Additional pool metadata")
57
- mu: Optional[float] = Field(None, description="Mean APY value")
58
- sigma: Optional[float] = Field(None, description="APY standard deviation")
59
- count: Optional[int] = Field(None, description="Number of data points")
54
+ poolMeta: str | None = Field(None, description="Additional pool metadata")
55
+ mu: float | None = Field(None, description="Mean APY value")
56
+ sigma: float | None = Field(None, description="APY standard deviation")
57
+ count: int | None = Field(None, description="Number of data points")
60
58
  outlier: bool = Field(False, description="Whether pool is an outlier")
61
- underlyingTokens: Optional[list[str]] = Field(
59
+ underlyingTokens: list[str] | None = Field(
62
60
  None, description="List of underlying token addresses"
63
61
  )
64
- il7d: Optional[float] = Field(None, description="7-day impermanent loss")
65
- apyBase7d: Optional[float] = Field(None, description="7-day base APY")
66
- apyMean30d: Optional[float] = Field(None, description="30-day mean APY")
67
- volumeUsd1d: Optional[float] = Field(None, description="24h volume in USD")
68
- volumeUsd7d: Optional[float] = Field(None, description="7-day volume in USD")
69
- apyBaseInception: Optional[float] = Field(
70
- None, description="Base APY since inception"
71
- )
62
+ il7d: float | None = Field(None, description="7-day impermanent loss")
63
+ apyBase7d: float | None = Field(None, description="7-day base APY")
64
+ apyMean30d: float | None = Field(None, description="30-day mean APY")
65
+ volumeUsd1d: float | None = Field(None, description="24h volume in USD")
66
+ volumeUsd7d: float | None = Field(None, description="7-day volume in USD")
67
+ apyBaseInception: float | None = Field(None, description="Base APY since inception")
72
68
 
73
69
 
74
70
  class FetchPoolsResponse(BaseModel):
@@ -76,7 +72,7 @@ class FetchPoolsResponse(BaseModel):
76
72
 
77
73
  status: str = Field("success", description="Response status")
78
74
  data: list[PoolData] = Field(default_factory=list, description="List of pool data")
79
- error: Optional[str] = Field(None, description="Error message if any")
75
+ error: str | None = Field(None, description="Error message if any")
80
76
 
81
77
 
82
78
  class DefiLlamaFetchPools(DefiLlamaBaseTool):
@@ -87,9 +83,9 @@ class DefiLlamaFetchPools(DefiLlamaBaseTool):
87
83
 
88
84
  Example:
89
85
  pools_tool = DefiLlamaFetchPools(
90
- skill_store=store,
86
+ ,
91
87
  agent_id="agent_123",
92
- agent_store=agent_store
88
+ agent=agent
93
89
  )
94
90
  result = await pools_tool._arun()
95
91
  """
@@ -1,102 +1,97 @@
1
- import logging
2
- from typing import Optional, TypedDict
3
-
4
- from intentkit.abstracts.skill import SkillStoreABC
5
- from intentkit.skills.base import SkillConfig, SkillState
6
- from intentkit.skills.dexscreener.base import DexScreenerBaseTool
7
- from intentkit.skills.dexscreener.get_pair_info import GetPairInfo
8
- from intentkit.skills.dexscreener.get_token_pairs import GetTokenPairs
9
- from intentkit.skills.dexscreener.get_tokens_info import GetTokensInfo
10
- from intentkit.skills.dexscreener.search_token import SearchToken
11
-
12
- # Cache skills at the system level, because they are stateless
13
- _cache: dict[str, DexScreenerBaseTool] = {}
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class SkillStates(TypedDict):
19
- search_token: SkillState
20
- get_pair_info: SkillState
21
- get_token_pairs: SkillState
22
- get_tokens_info: SkillState
23
-
24
-
25
- _SKILL_NAME_TO_CLASS_MAP: dict[str, type[DexScreenerBaseTool]] = {
26
- "search_token": SearchToken,
27
- "get_pair_info": GetPairInfo,
28
- "get_token_pairs": GetTokenPairs,
29
- "get_tokens_info": GetTokensInfo,
30
- }
31
-
32
-
33
- class Config(SkillConfig):
34
- """Configuration for DexScreener skills."""
35
-
36
- enabled: bool
37
- states: SkillStates
38
-
39
-
40
- async def get_skills(
41
- config: "Config",
42
- is_private: bool,
43
- store: SkillStoreABC,
44
- **_,
45
- ) -> list[DexScreenerBaseTool]:
46
- """Get all DexScreener skills.
47
-
48
- Args:
49
- config: The configuration for DexScreener skills.
50
- is_private: Whether to include private skills.
51
- store: The skill store for persisting data.
52
-
53
- Returns:
54
- A list of DexScreener skills.
55
- """
56
-
57
- available_skills = []
58
-
59
- # Include skills based on their state
60
- for skill_name, state in config["states"].items():
61
- if state == "disabled":
62
- continue
63
- elif state == "public" or (state == "private" and is_private):
64
- available_skills.append(skill_name)
65
-
66
- logger.debug(f"Available Skills {available_skills}")
67
- logger.debug(f"Hardcoded Skills {_SKILL_NAME_TO_CLASS_MAP}")
68
-
69
- # Get each skill using the cached getter
70
- result = []
71
- for name in available_skills:
72
- skill = get_dexscreener_skills(name, store)
73
- if skill:
74
- result.append(skill)
75
- return result
76
-
77
-
78
- def get_dexscreener_skills(
79
- name: str,
80
- store: SkillStoreABC,
81
- ) -> Optional[DexScreenerBaseTool]:
82
- """Get a DexScreener skill by name.
83
-
84
- Args:
85
- name: The name of the skill to get
86
- store: The skill store for persisting data
87
-
88
- Returns:
89
- The requested DexScreener skill
90
- """
91
-
92
- # Return from cache immediately if already exists
93
- if name in _cache:
94
- return _cache[name]
95
-
96
- skill_class = _SKILL_NAME_TO_CLASS_MAP.get(name)
97
- if not skill_class:
98
- logger.warning(f"Unknown Dexscreener skill: {name}")
99
- return None
100
-
101
- _cache[name] = skill_class(skill_store=store)
102
- return _cache[name]
1
+ import logging
2
+ from typing import TypedDict
3
+
4
+ from intentkit.skills.base import SkillConfig, SkillState
5
+ from intentkit.skills.dexscreener.base import DexScreenerBaseTool
6
+ from intentkit.skills.dexscreener.get_pair_info import GetPairInfo
7
+ from intentkit.skills.dexscreener.get_token_pairs import GetTokenPairs
8
+ from intentkit.skills.dexscreener.get_tokens_info import GetTokensInfo
9
+ from intentkit.skills.dexscreener.search_token import SearchToken
10
+
11
+ # Cache skills at the system level, because they are stateless
12
+ _cache: dict[str, DexScreenerBaseTool] = {}
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class SkillStates(TypedDict):
18
+ search_token: SkillState
19
+ get_pair_info: SkillState
20
+ get_token_pairs: SkillState
21
+ get_tokens_info: SkillState
22
+
23
+
24
+ _SKILL_NAME_TO_CLASS_MAP: dict[str, type[DexScreenerBaseTool]] = {
25
+ "search_token": SearchToken,
26
+ "get_pair_info": GetPairInfo,
27
+ "get_token_pairs": GetTokenPairs,
28
+ "get_tokens_info": GetTokensInfo,
29
+ }
30
+
31
+
32
+ class Config(SkillConfig):
33
+ """Configuration for DexScreener skills."""
34
+
35
+ enabled: bool
36
+ states: SkillStates
37
+
38
+
39
+ async def get_skills(
40
+ config: "Config",
41
+ is_private: bool,
42
+ **_,
43
+ ) -> list[DexScreenerBaseTool]:
44
+ """Get all DexScreener skills.
45
+
46
+ Args:
47
+ config: The configuration for DexScreener skills.
48
+ is_private: Whether to include private skills.
49
+
50
+ Returns:
51
+ A list of DexScreener skills.
52
+ """
53
+
54
+ available_skills = []
55
+
56
+ # Include skills based on their state
57
+ for skill_name, state in config["states"].items():
58
+ if state == "disabled":
59
+ continue
60
+ elif state == "public" or (state == "private" and is_private):
61
+ available_skills.append(skill_name)
62
+
63
+ logger.debug(f"Available Skills {available_skills}")
64
+ logger.debug(f"Hardcoded Skills {_SKILL_NAME_TO_CLASS_MAP}")
65
+
66
+ # Get each skill using the cached getter
67
+ result = []
68
+ for name in available_skills:
69
+ skill = get_dexscreener_skills(name)
70
+ if skill:
71
+ result.append(skill)
72
+ return result
73
+
74
+
75
+ def get_dexscreener_skills(
76
+ name: str,
77
+ ) -> DexScreenerBaseTool | None:
78
+ """Get a DexScreener skill by name.
79
+
80
+ Args:
81
+ name: The name of the skill to get
82
+
83
+ Returns:
84
+ The requested DexScreener skill
85
+ """
86
+
87
+ # Return from cache immediately if already exists
88
+ if name in _cache:
89
+ return _cache[name]
90
+
91
+ skill_class = _SKILL_NAME_TO_CLASS_MAP.get(name)
92
+ if not skill_class:
93
+ logger.warning(f"Unknown Dexscreener skill: {name}")
94
+ return None
95
+
96
+ _cache[name] = skill_class()
97
+ return _cache[name]
@@ -1,130 +1,125 @@
1
- import json
2
- import logging
3
- from typing import Any, Dict, Optional, Tuple
4
-
5
- import httpx
6
- from pydantic import Field
7
-
8
- from intentkit.abstracts.skill import SkillStoreABC
9
- from intentkit.skills.base import IntentKitSkill
10
- from intentkit.skills.dexscreener.utils import DEXSCREENER_BASE_URL
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
- # ApiResult still represents (success_data, error_data)
15
- ApiResult = Tuple[Optional[Dict[str, Any]], Optional[Dict[str, Any]]]
16
-
17
-
18
- class DexScreenerBaseTool(IntentKitSkill):
19
- """
20
- Generic base class for tools interacting with the Dex Screener API.
21
- Handles shared logic like API calls and error reporting via return values.
22
- """
23
-
24
- skill_store: SkillStoreABC = Field(
25
- description="The skill store for persisting data and configs."
26
- )
27
- base_url: str = DEXSCREENER_BASE_URL
28
-
29
- @property
30
- def category(self) -> str:
31
- return "dexscreener"
32
-
33
- async def _get(
34
- self,
35
- path: str,
36
- params: Optional[Dict[str, Any]] = None,
37
- ) -> ApiResult:
38
- """
39
- Makes an asynchronous GET request to the DexScreener API.
40
-
41
- Args:
42
- path: The API endpoint path (e.g., "/dex/search").
43
- params: Optional dictionary of query parameters.
44
-
45
- Returns:
46
- A tuple (data, error_details):
47
- - (dict, None): On HTTP 2xx success with valid JSON response.
48
- - (None, dict): On any error (API error, connection error,
49
- JSON parsing error, unexpected error). The dict
50
- contains details including an 'error_type'.
51
- """
52
- if not path.startswith("/"):
53
- path = "/" + path
54
-
55
- url = f"{self.base_url}{path}"
56
- headers = {"Accept": "application/json"}
57
- method = "GET"
58
-
59
- logger.debug(f"Calling DexScreener API: {method} {url} with params: {params}")
60
- response = None # Define response outside try block for access in except
61
-
62
- try:
63
- async with httpx.AsyncClient() as client:
64
- response = await client.request(
65
- method, url, params=params, headers=headers
66
- )
67
-
68
- # Attempt to parse JSON response text
69
- try:
70
- response_data = response.json()
71
- except json.JSONDecodeError as json_err:
72
- logger.error(
73
- f"Failed to parse JSON response from {url}. Status: {response.status_code}. Response text: {response.text}",
74
- exc_info=True,
75
- )
76
- error_details = {
77
- "error": "Failed to parse DexScreener API response",
78
- "error_type": "parsing_error",
79
- "status_code": response.status_code,
80
- "details": response.text, # Raw text causing the error
81
- "original_exception": str(json_err),
82
- "url": url,
83
- }
84
- return None, error_details # Return parsing error
85
-
86
- # Check HTTP status *after* attempting JSON parse
87
- if response.is_success: # 2xx
88
- logger.debug(
89
- f"DexScreener API success response status: {response.status_code}"
90
- )
91
- return response_data, None # Success
92
- else: # 4xx/5xx
93
- logger.warning(
94
- f"DexScreener API returned error status: {response.status_code} - {response.text}"
95
- )
96
- error_details = {
97
- "error": "DexScreener API request failed",
98
- "error_type": "api_error",
99
- "status_code": response.status_code,
100
- "response_body": response_data, # Parsed error body if available
101
- "url": url,
102
- }
103
- return None, error_details # Return API error
104
-
105
- except httpx.RequestError as req_err:
106
- logger.error(
107
- f"Request error connecting to DexScreener API: {req_err}", exc_info=True
108
- )
109
- error_details = {
110
- "error": "Failed to connect to DexScreener API",
111
- "error_type": "connection_error",
112
- "details": str(req_err),
113
- "url": url,
114
- }
115
- return None, error_details # Return connection error
116
-
117
- except Exception as e:
118
- # Catch any other unexpected errors during the process
119
- logger.exception(
120
- f"An unexpected error occurred during DexScreener API GET call: {e}"
121
- )
122
- status_code = response.status_code if response else None
123
- error_details = {
124
- "error": "An unexpected error occurred during API call",
125
- "error_type": "unexpected_error",
126
- "status_code": status_code, # Include if available
127
- "details": str(e),
128
- "url": url,
129
- }
130
- return None, error_details # Return unexpected error
1
+ import json
2
+ import logging
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+ from intentkit.skills.base import IntentKitSkill
8
+ from intentkit.skills.dexscreener.utils import DEXSCREENER_BASE_URL
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # ApiResult still represents (success_data, error_data)
13
+ ApiResult = tuple[dict[str, Any] | None, dict[str, Any] | None]
14
+
15
+
16
+ class DexScreenerBaseTool(IntentKitSkill):
17
+ """
18
+ Generic base class for tools interacting with the Dex Screener API.
19
+ Handles shared logic like API calls and error reporting via return values.
20
+ """
21
+
22
+ base_url: str = DEXSCREENER_BASE_URL
23
+
24
+ @property
25
+ def category(self) -> str:
26
+ return "dexscreener"
27
+
28
+ async def _get(
29
+ self,
30
+ path: str,
31
+ params: dict[str, Any] | None = None,
32
+ ) -> ApiResult:
33
+ """
34
+ Makes an asynchronous GET request to the DexScreener API.
35
+
36
+ Args:
37
+ path: The API endpoint path (e.g., "/dex/search").
38
+ params: Optional dictionary of query parameters.
39
+
40
+ Returns:
41
+ A tuple (data, error_details):
42
+ - (dict, None): On HTTP 2xx success with valid JSON response.
43
+ - (None, dict): On any error (API error, connection error,
44
+ JSON parsing error, unexpected error). The dict
45
+ contains details including an 'error_type'.
46
+ """
47
+ if not path.startswith("/"):
48
+ path = "/" + path
49
+
50
+ url = f"{self.base_url}{path}"
51
+ headers = {"Accept": "application/json"}
52
+ method = "GET"
53
+
54
+ logger.debug(f"Calling DexScreener API: {method} {url} with params: {params}")
55
+ response = None # Define response outside try block for access in except
56
+
57
+ try:
58
+ async with httpx.AsyncClient() as client:
59
+ response = await client.request(
60
+ method, url, params=params, headers=headers
61
+ )
62
+
63
+ # Attempt to parse JSON response text
64
+ try:
65
+ response_data = response.json()
66
+ except json.JSONDecodeError as json_err:
67
+ logger.error(
68
+ f"Failed to parse JSON response from {url}. Status: {response.status_code}. Response text: {response.text}",
69
+ exc_info=True,
70
+ )
71
+ error_details = {
72
+ "error": "Failed to parse DexScreener API response",
73
+ "error_type": "parsing_error",
74
+ "status_code": response.status_code,
75
+ "details": response.text, # Raw text causing the error
76
+ "original_exception": str(json_err),
77
+ "url": url,
78
+ }
79
+ return None, error_details # Return parsing error
80
+
81
+ # Check HTTP status *after* attempting JSON parse
82
+ if response.is_success: # 2xx
83
+ logger.debug(
84
+ f"DexScreener API success response status: {response.status_code}"
85
+ )
86
+ return response_data, None # Success
87
+ else: # 4xx/5xx
88
+ logger.warning(
89
+ f"DexScreener API returned error status: {response.status_code} - {response.text}"
90
+ )
91
+ error_details = {
92
+ "error": "DexScreener API request failed",
93
+ "error_type": "api_error",
94
+ "status_code": response.status_code,
95
+ "response_body": response_data, # Parsed error body if available
96
+ "url": url,
97
+ }
98
+ return None, error_details # Return API error
99
+
100
+ except httpx.RequestError as req_err:
101
+ logger.error(
102
+ f"Request error connecting to DexScreener API: {req_err}", exc_info=True
103
+ )
104
+ error_details = {
105
+ "error": "Failed to connect to DexScreener API",
106
+ "error_type": "connection_error",
107
+ "details": str(req_err),
108
+ "url": url,
109
+ }
110
+ return None, error_details # Return connection error
111
+
112
+ except Exception as e:
113
+ # Catch any other unexpected errors during the process
114
+ logger.exception(
115
+ f"An unexpected error occurred during DexScreener API GET call: {e}"
116
+ )
117
+ status_code = response.status_code if response else None
118
+ error_details = {
119
+ "error": "An unexpected error occurred during API call",
120
+ "error_type": "unexpected_error",
121
+ "status_code": status_code, # Include if available
122
+ "details": str(e),
123
+ "url": url,
124
+ }
125
+ return None, error_details # Return unexpected error
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Type
2
+ from typing import Any
3
3
 
4
4
  from pydantic import BaseModel, Field
5
5
 
@@ -39,7 +39,7 @@ class GetPairInfo(DexScreenerBaseTool):
39
39
  "market cap, FDV, transaction counts, and social links. "
40
40
  "Use this tool when you have a specific pair address and need detailed trading metrics."
41
41
  )
42
- args_schema: Type[BaseModel] = GetPairInfoInput
42
+ args_schema: type[BaseModel] = GetPairInfoInput
43
43
 
44
44
  async def _arun(
45
45
  self,
@@ -50,10 +50,9 @@ class GetPairInfo(DexScreenerBaseTool):
50
50
  """Implementation to get specific pair information."""
51
51
 
52
52
  # Apply rate limiting
53
- await self.user_rate_limit_by_category(
54
- user_id=f"{self.category}{self.name}",
53
+ await self.global_rate_limit_by_skill(
55
54
  limit=RATE_LIMITS["pairs"],
56
- minutes=1,
55
+ seconds=60,
57
56
  )
58
57
 
59
58
  logger.info(
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Any, Type
2
+ from typing import Any
3
3
 
4
4
  from pydantic import BaseModel, Field, ValidationError
5
5
 
@@ -44,7 +44,7 @@ class GetTokenPairs(DexScreenerBaseTool):
44
44
  "DEX information, liquidity, volume, and pricing data for each pair. "
45
45
  "Use this tool to analyze all available trading venues and liquidity sources for a specific token."
46
46
  )
47
- args_schema: Type[BaseModel] = GetTokenPairsInput
47
+ args_schema: type[BaseModel] = GetTokenPairsInput
48
48
 
49
49
  async def _arun(
50
50
  self,
@@ -55,10 +55,9 @@ class GetTokenPairs(DexScreenerBaseTool):
55
55
  """Implementation to get all pairs for a specific token."""
56
56
 
57
57
  # Apply rate limiting
58
- await self.user_rate_limit_by_category(
59
- user_id=f"{self.category}{self.name}",
58
+ await self.global_rate_limit_by_skill(
60
59
  limit=RATE_LIMITS["token_pairs"],
61
- minutes=1,
60
+ seconds=60,
62
61
  )
63
62
 
64
63
  logger.info(