intentkit 0.5.0__py3-none-any.whl → 0.5.2__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 (366) hide show
  1. intentkit/__init__.py +17 -0
  2. intentkit/abstracts/__init__.py +0 -0
  3. intentkit/abstracts/agent.py +60 -0
  4. intentkit/abstracts/api.py +4 -0
  5. intentkit/abstracts/engine.py +38 -0
  6. intentkit/abstracts/exception.py +9 -0
  7. intentkit/abstracts/graph.py +25 -0
  8. intentkit/abstracts/skill.py +129 -0
  9. intentkit/abstracts/twitter.py +54 -0
  10. intentkit/clients/__init__.py +14 -0
  11. intentkit/clients/cdp.py +53 -0
  12. intentkit/clients/twitter.py +445 -0
  13. intentkit/config/__init__.py +0 -0
  14. intentkit/config/config.py +164 -0
  15. intentkit/core/__init__.py +0 -0
  16. intentkit/core/agent.py +191 -0
  17. intentkit/core/api.py +40 -0
  18. intentkit/core/client.py +45 -0
  19. intentkit/core/credit.py +1767 -0
  20. intentkit/core/engine.py +1018 -0
  21. intentkit/core/node.py +223 -0
  22. intentkit/core/prompt.py +58 -0
  23. intentkit/core/skill.py +124 -0
  24. intentkit/models/agent.py +1689 -0
  25. intentkit/models/agent_data.py +810 -0
  26. intentkit/models/agent_schema.json +733 -0
  27. intentkit/models/app_setting.py +156 -0
  28. intentkit/models/base.py +9 -0
  29. intentkit/models/chat.py +581 -0
  30. intentkit/models/conversation.py +286 -0
  31. intentkit/models/credit.py +1406 -0
  32. intentkit/models/db.py +120 -0
  33. intentkit/models/db_mig.py +102 -0
  34. intentkit/models/generator.py +347 -0
  35. intentkit/models/llm.py +746 -0
  36. intentkit/models/redis.py +132 -0
  37. intentkit/models/skill.py +466 -0
  38. intentkit/models/user.py +243 -0
  39. intentkit/skills/__init__.py +12 -0
  40. intentkit/skills/acolyt/__init__.py +83 -0
  41. intentkit/skills/acolyt/acolyt.jpg +0 -0
  42. intentkit/skills/acolyt/ask.py +128 -0
  43. intentkit/skills/acolyt/base.py +28 -0
  44. intentkit/skills/acolyt/schema.json +89 -0
  45. intentkit/skills/aixbt/README.md +71 -0
  46. intentkit/skills/aixbt/__init__.py +73 -0
  47. intentkit/skills/aixbt/aixbt.jpg +0 -0
  48. intentkit/skills/aixbt/base.py +21 -0
  49. intentkit/skills/aixbt/projects.py +153 -0
  50. intentkit/skills/aixbt/schema.json +99 -0
  51. intentkit/skills/allora/__init__.py +83 -0
  52. intentkit/skills/allora/allora.jpeg +0 -0
  53. intentkit/skills/allora/base.py +28 -0
  54. intentkit/skills/allora/price.py +130 -0
  55. intentkit/skills/allora/schema.json +89 -0
  56. intentkit/skills/base.py +174 -0
  57. intentkit/skills/carv/README.md +95 -0
  58. intentkit/skills/carv/__init__.py +121 -0
  59. intentkit/skills/carv/base.py +183 -0
  60. intentkit/skills/carv/carv.webp +0 -0
  61. intentkit/skills/carv/fetch_news.py +92 -0
  62. intentkit/skills/carv/onchain_query.py +164 -0
  63. intentkit/skills/carv/schema.json +137 -0
  64. intentkit/skills/carv/token_info_and_price.py +110 -0
  65. intentkit/skills/cdp/__init__.py +137 -0
  66. intentkit/skills/cdp/base.py +21 -0
  67. intentkit/skills/cdp/cdp.png +0 -0
  68. intentkit/skills/cdp/get_balance.py +81 -0
  69. intentkit/skills/cdp/schema.json +473 -0
  70. intentkit/skills/chainlist/README.md +38 -0
  71. intentkit/skills/chainlist/__init__.py +54 -0
  72. intentkit/skills/chainlist/base.py +21 -0
  73. intentkit/skills/chainlist/chain_lookup.py +208 -0
  74. intentkit/skills/chainlist/chainlist.png +0 -0
  75. intentkit/skills/chainlist/schema.json +47 -0
  76. intentkit/skills/common/__init__.py +82 -0
  77. intentkit/skills/common/base.py +21 -0
  78. intentkit/skills/common/common.jpg +0 -0
  79. intentkit/skills/common/current_time.py +84 -0
  80. intentkit/skills/common/schema.json +57 -0
  81. intentkit/skills/cookiefun/README.md +121 -0
  82. intentkit/skills/cookiefun/__init__.py +78 -0
  83. intentkit/skills/cookiefun/base.py +41 -0
  84. intentkit/skills/cookiefun/constants.py +18 -0
  85. intentkit/skills/cookiefun/cookiefun.png +0 -0
  86. intentkit/skills/cookiefun/get_account_details.py +171 -0
  87. intentkit/skills/cookiefun/get_account_feed.py +282 -0
  88. intentkit/skills/cookiefun/get_account_smart_followers.py +181 -0
  89. intentkit/skills/cookiefun/get_sectors.py +128 -0
  90. intentkit/skills/cookiefun/schema.json +155 -0
  91. intentkit/skills/cookiefun/search_accounts.py +225 -0
  92. intentkit/skills/cryptocompare/__init__.py +130 -0
  93. intentkit/skills/cryptocompare/api.py +159 -0
  94. intentkit/skills/cryptocompare/base.py +303 -0
  95. intentkit/skills/cryptocompare/cryptocompare.png +0 -0
  96. intentkit/skills/cryptocompare/fetch_news.py +96 -0
  97. intentkit/skills/cryptocompare/fetch_price.py +99 -0
  98. intentkit/skills/cryptocompare/fetch_top_exchanges.py +113 -0
  99. intentkit/skills/cryptocompare/fetch_top_market_cap.py +109 -0
  100. intentkit/skills/cryptocompare/fetch_top_volume.py +108 -0
  101. intentkit/skills/cryptocompare/fetch_trading_signals.py +107 -0
  102. intentkit/skills/cryptocompare/schema.json +168 -0
  103. intentkit/skills/cryptopanic/__init__.py +108 -0
  104. intentkit/skills/cryptopanic/base.py +51 -0
  105. intentkit/skills/cryptopanic/cryptopanic.png +0 -0
  106. intentkit/skills/cryptopanic/fetch_crypto_news.py +153 -0
  107. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +136 -0
  108. intentkit/skills/cryptopanic/schema.json +103 -0
  109. intentkit/skills/dapplooker/README.md +92 -0
  110. intentkit/skills/dapplooker/__init__.py +83 -0
  111. intentkit/skills/dapplooker/base.py +26 -0
  112. intentkit/skills/dapplooker/dapplooker.jpg +0 -0
  113. intentkit/skills/dapplooker/dapplooker_token_data.py +476 -0
  114. intentkit/skills/dapplooker/schema.json +91 -0
  115. intentkit/skills/defillama/__init__.py +323 -0
  116. intentkit/skills/defillama/api.py +315 -0
  117. intentkit/skills/defillama/base.py +135 -0
  118. intentkit/skills/defillama/coins/__init__.py +0 -0
  119. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +116 -0
  120. intentkit/skills/defillama/coins/fetch_block.py +98 -0
  121. intentkit/skills/defillama/coins/fetch_current_prices.py +105 -0
  122. intentkit/skills/defillama/coins/fetch_first_price.py +100 -0
  123. intentkit/skills/defillama/coins/fetch_historical_prices.py +110 -0
  124. intentkit/skills/defillama/coins/fetch_price_chart.py +109 -0
  125. intentkit/skills/defillama/coins/fetch_price_percentage.py +93 -0
  126. intentkit/skills/defillama/config/__init__.py +0 -0
  127. intentkit/skills/defillama/config/chains.py +433 -0
  128. intentkit/skills/defillama/defillama.jpeg +0 -0
  129. intentkit/skills/defillama/fees/__init__.py +0 -0
  130. intentkit/skills/defillama/fees/fetch_fees_overview.py +130 -0
  131. intentkit/skills/defillama/schema.json +383 -0
  132. intentkit/skills/defillama/stablecoins/__init__.py +0 -0
  133. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +100 -0
  134. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +129 -0
  135. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +83 -0
  136. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +126 -0
  137. intentkit/skills/defillama/tests/__init__.py +0 -0
  138. intentkit/skills/defillama/tests/api_integration.test.py +192 -0
  139. intentkit/skills/defillama/tests/api_unit.test.py +583 -0
  140. intentkit/skills/defillama/tvl/__init__.py +0 -0
  141. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +106 -0
  142. intentkit/skills/defillama/tvl/fetch_chains.py +107 -0
  143. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +91 -0
  144. intentkit/skills/defillama/tvl/fetch_protocol.py +207 -0
  145. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +93 -0
  146. intentkit/skills/defillama/tvl/fetch_protocols.py +196 -0
  147. intentkit/skills/defillama/volumes/__init__.py +0 -0
  148. intentkit/skills/defillama/volumes/fetch_dex_overview.py +157 -0
  149. intentkit/skills/defillama/volumes/fetch_dex_summary.py +123 -0
  150. intentkit/skills/defillama/volumes/fetch_options_overview.py +131 -0
  151. intentkit/skills/defillama/yields/__init__.py +0 -0
  152. intentkit/skills/defillama/yields/fetch_pool_chart.py +100 -0
  153. intentkit/skills/defillama/yields/fetch_pools.py +126 -0
  154. intentkit/skills/dexscreener/__init__.py +93 -0
  155. intentkit/skills/dexscreener/base.py +133 -0
  156. intentkit/skills/dexscreener/dexscreener.png +0 -0
  157. intentkit/skills/dexscreener/model/__init__.py +0 -0
  158. intentkit/skills/dexscreener/model/search_token_response.py +82 -0
  159. intentkit/skills/dexscreener/schema.json +48 -0
  160. intentkit/skills/dexscreener/search_token.py +321 -0
  161. intentkit/skills/dune_analytics/__init__.py +103 -0
  162. intentkit/skills/dune_analytics/base.py +46 -0
  163. intentkit/skills/dune_analytics/dune.png +0 -0
  164. intentkit/skills/dune_analytics/fetch_kol_buys.py +128 -0
  165. intentkit/skills/dune_analytics/fetch_nation_metrics.py +237 -0
  166. intentkit/skills/dune_analytics/schema.json +99 -0
  167. intentkit/skills/elfa/README.md +100 -0
  168. intentkit/skills/elfa/__init__.py +123 -0
  169. intentkit/skills/elfa/base.py +28 -0
  170. intentkit/skills/elfa/elfa.jpg +0 -0
  171. intentkit/skills/elfa/mention.py +504 -0
  172. intentkit/skills/elfa/schema.json +153 -0
  173. intentkit/skills/elfa/stats.py +118 -0
  174. intentkit/skills/elfa/tokens.py +126 -0
  175. intentkit/skills/enso/README.md +75 -0
  176. intentkit/skills/enso/__init__.py +114 -0
  177. intentkit/skills/enso/abi/__init__.py +0 -0
  178. intentkit/skills/enso/abi/approval.py +279 -0
  179. intentkit/skills/enso/abi/erc20.py +14 -0
  180. intentkit/skills/enso/abi/route.py +129 -0
  181. intentkit/skills/enso/base.py +44 -0
  182. intentkit/skills/enso/best_yield.py +286 -0
  183. intentkit/skills/enso/enso.jpg +0 -0
  184. intentkit/skills/enso/networks.py +105 -0
  185. intentkit/skills/enso/prices.py +93 -0
  186. intentkit/skills/enso/route.py +300 -0
  187. intentkit/skills/enso/schema.json +212 -0
  188. intentkit/skills/enso/tokens.py +223 -0
  189. intentkit/skills/enso/wallet.py +381 -0
  190. intentkit/skills/github/README.md +63 -0
  191. intentkit/skills/github/__init__.py +54 -0
  192. intentkit/skills/github/base.py +21 -0
  193. intentkit/skills/github/github.jpg +0 -0
  194. intentkit/skills/github/github_search.py +183 -0
  195. intentkit/skills/github/schema.json +59 -0
  196. intentkit/skills/heurist/__init__.py +143 -0
  197. intentkit/skills/heurist/base.py +26 -0
  198. intentkit/skills/heurist/heurist.png +0 -0
  199. intentkit/skills/heurist/image_generation_animagine_xl.py +162 -0
  200. intentkit/skills/heurist/image_generation_arthemy_comics.py +162 -0
  201. intentkit/skills/heurist/image_generation_arthemy_real.py +162 -0
  202. intentkit/skills/heurist/image_generation_braindance.py +162 -0
  203. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +162 -0
  204. intentkit/skills/heurist/image_generation_flux_1_dev.py +162 -0
  205. intentkit/skills/heurist/image_generation_sdxl.py +161 -0
  206. intentkit/skills/heurist/schema.json +196 -0
  207. intentkit/skills/lifi/README.md +294 -0
  208. intentkit/skills/lifi/__init__.py +141 -0
  209. intentkit/skills/lifi/base.py +21 -0
  210. intentkit/skills/lifi/lifi.png +0 -0
  211. intentkit/skills/lifi/schema.json +89 -0
  212. intentkit/skills/lifi/token_execute.py +472 -0
  213. intentkit/skills/lifi/token_quote.py +190 -0
  214. intentkit/skills/lifi/utils.py +656 -0
  215. intentkit/skills/moralis/README.md +490 -0
  216. intentkit/skills/moralis/__init__.py +110 -0
  217. intentkit/skills/moralis/api.py +281 -0
  218. intentkit/skills/moralis/base.py +55 -0
  219. intentkit/skills/moralis/fetch_chain_portfolio.py +191 -0
  220. intentkit/skills/moralis/fetch_nft_portfolio.py +284 -0
  221. intentkit/skills/moralis/fetch_solana_portfolio.py +331 -0
  222. intentkit/skills/moralis/fetch_wallet_portfolio.py +301 -0
  223. intentkit/skills/moralis/moralis.png +0 -0
  224. intentkit/skills/moralis/schema.json +156 -0
  225. intentkit/skills/moralis/tests/__init__.py +0 -0
  226. intentkit/skills/moralis/tests/test_wallet.py +511 -0
  227. intentkit/skills/nation/__init__.py +62 -0
  228. intentkit/skills/nation/base.py +31 -0
  229. intentkit/skills/nation/nation.png +0 -0
  230. intentkit/skills/nation/nft_check.py +106 -0
  231. intentkit/skills/nation/schema.json +58 -0
  232. intentkit/skills/openai/__init__.py +107 -0
  233. intentkit/skills/openai/base.py +32 -0
  234. intentkit/skills/openai/dalle_image_generation.py +128 -0
  235. intentkit/skills/openai/gpt_image_generation.py +152 -0
  236. intentkit/skills/openai/gpt_image_to_image.py +186 -0
  237. intentkit/skills/openai/image_to_text.py +126 -0
  238. intentkit/skills/openai/openai.png +0 -0
  239. intentkit/skills/openai/schema.json +139 -0
  240. intentkit/skills/portfolio/README.md +55 -0
  241. intentkit/skills/portfolio/__init__.py +151 -0
  242. intentkit/skills/portfolio/base.py +107 -0
  243. intentkit/skills/portfolio/constants.py +9 -0
  244. intentkit/skills/portfolio/moralis.png +0 -0
  245. intentkit/skills/portfolio/schema.json +237 -0
  246. intentkit/skills/portfolio/token_balances.py +155 -0
  247. intentkit/skills/portfolio/wallet_approvals.py +102 -0
  248. intentkit/skills/portfolio/wallet_defi_positions.py +80 -0
  249. intentkit/skills/portfolio/wallet_history.py +155 -0
  250. intentkit/skills/portfolio/wallet_net_worth.py +112 -0
  251. intentkit/skills/portfolio/wallet_nfts.py +139 -0
  252. intentkit/skills/portfolio/wallet_profitability.py +101 -0
  253. intentkit/skills/portfolio/wallet_profitability_summary.py +91 -0
  254. intentkit/skills/portfolio/wallet_stats.py +79 -0
  255. intentkit/skills/portfolio/wallet_swaps.py +147 -0
  256. intentkit/skills/skills.toml +103 -0
  257. intentkit/skills/slack/__init__.py +98 -0
  258. intentkit/skills/slack/base.py +55 -0
  259. intentkit/skills/slack/get_channel.py +109 -0
  260. intentkit/skills/slack/get_message.py +136 -0
  261. intentkit/skills/slack/schedule_message.py +92 -0
  262. intentkit/skills/slack/schema.json +135 -0
  263. intentkit/skills/slack/send_message.py +81 -0
  264. intentkit/skills/slack/slack.jpg +0 -0
  265. intentkit/skills/system/__init__.py +90 -0
  266. intentkit/skills/system/base.py +22 -0
  267. intentkit/skills/system/read_agent_api_key.py +87 -0
  268. intentkit/skills/system/regenerate_agent_api_key.py +77 -0
  269. intentkit/skills/system/schema.json +53 -0
  270. intentkit/skills/system/system.svg +76 -0
  271. intentkit/skills/tavily/README.md +86 -0
  272. intentkit/skills/tavily/__init__.py +91 -0
  273. intentkit/skills/tavily/base.py +27 -0
  274. intentkit/skills/tavily/schema.json +119 -0
  275. intentkit/skills/tavily/tavily.jpg +0 -0
  276. intentkit/skills/tavily/tavily_extract.py +147 -0
  277. intentkit/skills/tavily/tavily_search.py +139 -0
  278. intentkit/skills/token/README.md +89 -0
  279. intentkit/skills/token/__init__.py +107 -0
  280. intentkit/skills/token/base.py +154 -0
  281. intentkit/skills/token/constants.py +9 -0
  282. intentkit/skills/token/erc20_transfers.py +145 -0
  283. intentkit/skills/token/moralis.png +0 -0
  284. intentkit/skills/token/schema.json +141 -0
  285. intentkit/skills/token/token_analytics.py +81 -0
  286. intentkit/skills/token/token_price.py +132 -0
  287. intentkit/skills/token/token_search.py +121 -0
  288. intentkit/skills/twitter/__init__.py +146 -0
  289. intentkit/skills/twitter/base.py +68 -0
  290. intentkit/skills/twitter/follow_user.py +69 -0
  291. intentkit/skills/twitter/get_mentions.py +124 -0
  292. intentkit/skills/twitter/get_timeline.py +111 -0
  293. intentkit/skills/twitter/get_user_by_username.py +84 -0
  294. intentkit/skills/twitter/get_user_tweets.py +123 -0
  295. intentkit/skills/twitter/like_tweet.py +65 -0
  296. intentkit/skills/twitter/post_tweet.py +90 -0
  297. intentkit/skills/twitter/reply_tweet.py +98 -0
  298. intentkit/skills/twitter/retweet.py +76 -0
  299. intentkit/skills/twitter/schema.json +258 -0
  300. intentkit/skills/twitter/search_tweets.py +115 -0
  301. intentkit/skills/twitter/twitter.png +0 -0
  302. intentkit/skills/unrealspeech/__init__.py +55 -0
  303. intentkit/skills/unrealspeech/base.py +21 -0
  304. intentkit/skills/unrealspeech/schema.json +100 -0
  305. intentkit/skills/unrealspeech/text_to_speech.py +177 -0
  306. intentkit/skills/unrealspeech/unrealspeech.jpg +0 -0
  307. intentkit/skills/venice_audio/__init__.py +106 -0
  308. intentkit/skills/venice_audio/base.py +119 -0
  309. intentkit/skills/venice_audio/input.py +41 -0
  310. intentkit/skills/venice_audio/schema.json +152 -0
  311. intentkit/skills/venice_audio/venice_audio.py +240 -0
  312. intentkit/skills/venice_audio/venice_logo.jpg +0 -0
  313. intentkit/skills/venice_image/README.md +119 -0
  314. intentkit/skills/venice_image/__init__.py +154 -0
  315. intentkit/skills/venice_image/api.py +138 -0
  316. intentkit/skills/venice_image/base.py +188 -0
  317. intentkit/skills/venice_image/config.py +35 -0
  318. intentkit/skills/venice_image/image_enhance/README.md +119 -0
  319. intentkit/skills/venice_image/image_enhance/__init__.py +0 -0
  320. intentkit/skills/venice_image/image_enhance/image_enhance.py +80 -0
  321. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +23 -0
  322. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +40 -0
  323. intentkit/skills/venice_image/image_generation/README.md +144 -0
  324. intentkit/skills/venice_image/image_generation/__init__.py +0 -0
  325. intentkit/skills/venice_image/image_generation/image_generation_base.py +117 -0
  326. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -0
  327. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -0
  328. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -0
  329. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -0
  330. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -0
  331. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -0
  332. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -0
  333. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -0
  334. intentkit/skills/venice_image/image_upscale/README.md +111 -0
  335. intentkit/skills/venice_image/image_upscale/__init__.py +0 -0
  336. intentkit/skills/venice_image/image_upscale/image_upscale.py +90 -0
  337. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +23 -0
  338. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -0
  339. intentkit/skills/venice_image/image_vision/README.md +112 -0
  340. intentkit/skills/venice_image/image_vision/__init__.py +0 -0
  341. intentkit/skills/venice_image/image_vision/image_vision.py +100 -0
  342. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -0
  343. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -0
  344. intentkit/skills/venice_image/schema.json +267 -0
  345. intentkit/skills/venice_image/utils.py +78 -0
  346. intentkit/skills/venice_image/venice_image.jpg +0 -0
  347. intentkit/skills/web_scraper/README.md +82 -0
  348. intentkit/skills/web_scraper/__init__.py +92 -0
  349. intentkit/skills/web_scraper/base.py +21 -0
  350. intentkit/skills/web_scraper/langchain.png +0 -0
  351. intentkit/skills/web_scraper/schema.json +115 -0
  352. intentkit/skills/web_scraper/scrape_and_index.py +327 -0
  353. intentkit/utils/__init__.py +1 -0
  354. intentkit/utils/chain.py +436 -0
  355. intentkit/utils/error.py +134 -0
  356. intentkit/utils/logging.py +70 -0
  357. intentkit/utils/middleware.py +61 -0
  358. intentkit/utils/random.py +16 -0
  359. intentkit/utils/s3.py +267 -0
  360. intentkit/utils/slack_alert.py +79 -0
  361. intentkit/utils/tx.py +37 -0
  362. {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/METADATA +1 -1
  363. intentkit-0.5.2.dist-info/RECORD +365 -0
  364. intentkit-0.5.0.dist-info/RECORD +0 -4
  365. {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/WHEEL +0 -0
  366. {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,130 @@
1
+ """CryptoCompare skills."""
2
+
3
+ import logging
4
+ from typing import TypedDict
5
+
6
+ from intentkit.abstracts.skill import SkillStoreABC
7
+ from intentkit.skills.base import SkillConfig, SkillState
8
+ from intentkit.skills.cryptocompare.base import CryptoCompareBaseTool
9
+ from intentkit.skills.cryptocompare.fetch_news import CryptoCompareFetchNews
10
+ from intentkit.skills.cryptocompare.fetch_price import CryptoCompareFetchPrice
11
+ from intentkit.skills.cryptocompare.fetch_top_exchanges import (
12
+ CryptoCompareFetchTopExchanges,
13
+ )
14
+ from intentkit.skills.cryptocompare.fetch_top_market_cap import (
15
+ CryptoCompareFetchTopMarketCap,
16
+ )
17
+ from intentkit.skills.cryptocompare.fetch_top_volume import CryptoCompareFetchTopVolume
18
+ from intentkit.skills.cryptocompare.fetch_trading_signals import (
19
+ CryptoCompareFetchTradingSignals,
20
+ )
21
+
22
+ # Cache skills at the system level, because they are stateless
23
+ _cache: dict[str, CryptoCompareBaseTool] = {}
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ class SkillStates(TypedDict):
29
+ fetch_news: SkillState
30
+ fetch_price: SkillState
31
+ fetch_trading_signals: SkillState
32
+ fetch_top_market_cap: SkillState
33
+ fetch_top_exchanges: SkillState
34
+ fetch_top_volume: SkillState
35
+
36
+
37
+ class Config(SkillConfig):
38
+ """Configuration for CryptoCompare skills."""
39
+
40
+ states: SkillStates
41
+ api_key: str
42
+
43
+
44
+ async def get_skills(
45
+ config: "Config",
46
+ is_private: bool,
47
+ store: SkillStoreABC,
48
+ **_,
49
+ ) -> list[CryptoCompareBaseTool]:
50
+ """Get all CryptoCompare skills.
51
+
52
+ Args:
53
+ config: The configuration for CryptoCompare skills.
54
+ is_private: Whether to include private skills.
55
+ store: The skill store for persisting data.
56
+
57
+ Returns:
58
+ A list of CryptoCompare skills.
59
+ """
60
+ available_skills = []
61
+
62
+ # Include skills based on their state
63
+ for skill_name, state in config["states"].items():
64
+ if state == "disabled":
65
+ continue
66
+ elif state == "public" or (state == "private" and is_private):
67
+ available_skills.append(skill_name)
68
+
69
+ # Get each skill using the cached getter
70
+ result = []
71
+ for name in available_skills:
72
+ skill = get_cryptocompare_skill(name, store)
73
+ if skill:
74
+ result.append(skill)
75
+ return result
76
+
77
+
78
+ def get_cryptocompare_skill(
79
+ name: str,
80
+ store: SkillStoreABC,
81
+ ) -> CryptoCompareBaseTool:
82
+ """Get a CryptoCompare 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 CryptoCompare skill
90
+ """
91
+
92
+ if name == "fetch_news":
93
+ if name not in _cache:
94
+ _cache[name] = CryptoCompareFetchNews(
95
+ skill_store=store,
96
+ )
97
+ return _cache[name]
98
+ elif name == "fetch_price":
99
+ if name not in _cache:
100
+ _cache[name] = CryptoCompareFetchPrice(
101
+ skill_store=store,
102
+ )
103
+ return _cache[name]
104
+ elif name == "fetch_trading_signals":
105
+ if name not in _cache:
106
+ _cache[name] = CryptoCompareFetchTradingSignals(
107
+ skill_store=store,
108
+ )
109
+ return _cache[name]
110
+ elif name == "fetch_top_market_cap":
111
+ if name not in _cache:
112
+ _cache[name] = CryptoCompareFetchTopMarketCap(
113
+ skill_store=store,
114
+ )
115
+ return _cache[name]
116
+ elif name == "fetch_top_exchanges":
117
+ if name not in _cache:
118
+ _cache[name] = CryptoCompareFetchTopExchanges(
119
+ skill_store=store,
120
+ )
121
+ return _cache[name]
122
+ elif name == "fetch_top_volume":
123
+ if name not in _cache:
124
+ _cache[name] = CryptoCompareFetchTopVolume(
125
+ skill_store=store,
126
+ )
127
+ return _cache[name]
128
+ else:
129
+ logger.warning(f"Unknown CryptoCompare skill: {name}")
130
+ return None
@@ -0,0 +1,159 @@
1
+ """CryptoCompare API implementation and shared schemas."""
2
+
3
+ import time
4
+ from typing import List
5
+
6
+ import httpx
7
+ from pydantic import BaseModel, Field
8
+
9
+ CRYPTO_COMPARE_BASE_URL = "https://min-api.cryptocompare.com"
10
+
11
+
12
+ # Input Schemas
13
+ class FetchNewsInput(BaseModel):
14
+ """Input schema for fetching news."""
15
+
16
+ token: str = Field(
17
+ ..., description="Token symbol to fetch news for (e.g., BTC, ETH, SOL)"
18
+ )
19
+
20
+
21
+ class FetchPriceInput(BaseModel):
22
+ """Input schema for fetching crypto prices."""
23
+
24
+ from_symbol: str = Field(
25
+ ...,
26
+ description="Base cryptocurrency symbol to get prices for (e.g., 'BTC', 'ETH')",
27
+ )
28
+ to_symbols: List[str] = Field(
29
+ ...,
30
+ description="List of target currencies (fiat or crypto) (e.g., ['USD', 'EUR', 'JPY'])",
31
+ )
32
+
33
+
34
+ class FetchTradingSignalsInput(BaseModel):
35
+ """Input schema for fetching trading signals."""
36
+
37
+ from_symbol: str = Field(
38
+ ...,
39
+ description="Cryptocurrency symbol to fetch trading signals for (e.g., 'BTC')",
40
+ )
41
+
42
+
43
+ class FetchTopMarketCapInput(BaseModel):
44
+ """Input schema for fetching top cryptocurrencies by market cap."""
45
+
46
+ to_symbol: str = Field(
47
+ "USD",
48
+ description="Quote currency for market cap calculation (e.g., 'USD', 'EUR')",
49
+ )
50
+
51
+
52
+ class FetchTopExchangesInput(BaseModel):
53
+ """Input schema for fetching top exchanges for a trading pair."""
54
+
55
+ from_symbol: str = Field(
56
+ ..., description="Base cryptocurrency symbol for the trading pair (e.g., 'BTC')"
57
+ )
58
+ to_symbol: str = Field(
59
+ "USD",
60
+ description="Quote currency symbol for the trading pair. Defaults to 'USD'",
61
+ )
62
+
63
+
64
+ class FetchTopVolumeInput(BaseModel):
65
+ """Input schema for fetching top cryptocurrencies by trading volume."""
66
+
67
+ to_symbol: str = Field(
68
+ "USD", description="Quote currency for volume calculation. Defaults to 'USD'"
69
+ )
70
+
71
+
72
+ # API Functions
73
+ async def fetch_price(api_key: str, from_symbol: str, to_symbols: List[str]) -> dict:
74
+ """
75
+ Fetch current price for a cryptocurrency in multiple currencies.
76
+ """
77
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/price"
78
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
79
+ params = {"fsym": from_symbol.upper(), "tsyms": ",".join(to_symbols)}
80
+ async with httpx.AsyncClient() as client:
81
+ response = await client.get(url, params=params, headers=headers)
82
+ if response.status_code != 200:
83
+ return {"error": f"API returned status code {response.status_code}"}
84
+ return response.json()
85
+
86
+
87
+ async def fetch_trading_signals(api_key: str, from_symbol: str) -> dict:
88
+ """
89
+ Fetch the latest trading signals.
90
+ """
91
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/tradingsignals/intotheblock/latest"
92
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
93
+ params = {"fsym": from_symbol.upper()}
94
+ async with httpx.AsyncClient() as client:
95
+ response = await client.get(url, params=params, headers=headers)
96
+ if response.status_code != 200:
97
+ return {"error": f"API returned status code {response.status_code}"}
98
+ return response.json()
99
+
100
+
101
+ async def fetch_top_market_cap(
102
+ api_key: str, limit: int, to_symbol: str = "USD"
103
+ ) -> dict:
104
+ """
105
+ Fetch top cryptocurrencies by market cap.
106
+ """
107
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/top/mktcapfull"
108
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
109
+ params = {"limit": limit, "tsym": to_symbol.upper()}
110
+ async with httpx.AsyncClient() as client:
111
+ response = await client.get(url, params=params, headers=headers)
112
+ if response.status_code != 200:
113
+ return {"error": f"API returned status code {response.status_code}"}
114
+ return response.json()
115
+
116
+
117
+ async def fetch_top_exchanges(
118
+ api_key: str, from_symbol: str, to_symbol: str = "USD"
119
+ ) -> dict:
120
+ """
121
+ Fetch top exchanges for a cryptocurrency pair.
122
+ """
123
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/top/exchanges"
124
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
125
+ params = {"fsym": from_symbol.upper(), "tsym": to_symbol.upper()}
126
+ async with httpx.AsyncClient() as client:
127
+ response = await client.get(url, params=params, headers=headers)
128
+ if response.status_code != 200:
129
+ return {"error": f"API returned status code {response.status_code}"}
130
+ return response.json()
131
+
132
+
133
+ async def fetch_top_volume(api_key: str, limit: int, to_symbol: str = "USD") -> dict:
134
+ """
135
+ Fetch top cryptocurrencies by total volume.
136
+ """
137
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/top/totalvolfull"
138
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
139
+ params = {"limit": limit, "tsym": to_symbol.upper()}
140
+ async with httpx.AsyncClient() as client:
141
+ response = await client.get(url, params=params, headers=headers)
142
+ if response.status_code != 200:
143
+ return {"error": f"API returned status code {response.status_code}"}
144
+ return response.json()
145
+
146
+
147
+ async def fetch_news(api_key: str, token: str, timestamp: int = None) -> dict:
148
+ """
149
+ Fetch news for a specific token and timestamp.
150
+ """
151
+ if timestamp is None:
152
+ timestamp = int(time.time())
153
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/v2/news/?lang=EN&lTs={timestamp}&categories={token}&sign=true"
154
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
155
+ async with httpx.AsyncClient() as client:
156
+ response = await client.get(url, headers=headers)
157
+ if response.status_code != 200:
158
+ return {"error": f"API returned status code {response.status_code}"}
159
+ return response.json()
@@ -0,0 +1,303 @@
1
+ """Base class for all CryptoCompare tools."""
2
+
3
+ import logging
4
+ from datetime import datetime, timedelta, timezone
5
+ from typing import Any, Dict, List, Type
6
+
7
+ import httpx
8
+ from pydantic import BaseModel, Field
9
+
10
+ from intentkit.abstracts.exception import RateLimitExceeded
11
+ from intentkit.abstracts.skill import SkillStoreABC
12
+ from intentkit.skills.base import IntentKitSkill
13
+
14
+ CRYPTO_COMPARE_BASE_URL = "https://min-api.cryptocompare.com"
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class CryptoCompareBaseTool(IntentKitSkill):
20
+ """Base class for CryptoCompare tools.
21
+
22
+ This class provides common functionality for all CryptoCompare API tools:
23
+ - Rate limiting
24
+ - API client handling
25
+ - State management through skill_store
26
+ """
27
+
28
+ name: str = Field(description="The name of the tool")
29
+ description: str = Field(description="A description of what the tool does")
30
+ args_schema: Type[BaseModel]
31
+ skill_store: SkillStoreABC = Field(
32
+ description="The skill store for persisting data"
33
+ )
34
+
35
+ @property
36
+ def category(self) -> str:
37
+ return "cryptocompare"
38
+
39
+ async def check_rate_limit(
40
+ self, agent_id: str, max_requests: int = 1, interval: int = 15
41
+ ) -> None:
42
+ """Check if the rate limit has been exceeded.
43
+
44
+ Args:
45
+ agent_id: The ID of the agent.
46
+ max_requests: Maximum number of requests allowed within the rate limit window.
47
+ interval: Time interval in minutes for the rate limit window.
48
+
49
+ Raises:
50
+ RateLimitExceeded: If the rate limit has been exceeded.
51
+ """
52
+ rate_limit = await self.skill_store.get_agent_skill_data(
53
+ agent_id, self.name, "rate_limit"
54
+ )
55
+
56
+ current_time = datetime.now(tz=timezone.utc)
57
+
58
+ if (
59
+ rate_limit
60
+ and rate_limit.get("reset_time")
61
+ and rate_limit["count"] is not None
62
+ and datetime.fromisoformat(rate_limit["reset_time"]) > current_time
63
+ ):
64
+ if rate_limit["count"] >= max_requests:
65
+ raise RateLimitExceeded("Rate limit exceeded")
66
+
67
+ rate_limit["count"] += 1
68
+ await self.skill_store.save_agent_skill_data(
69
+ agent_id, self.name, "rate_limit", rate_limit
70
+ )
71
+
72
+ return
73
+
74
+ # If no rate limit exists or it has expired, create a new one
75
+ new_rate_limit = {
76
+ "count": 1,
77
+ "reset_time": (current_time + timedelta(minutes=interval)).isoformat(),
78
+ }
79
+ await self.skill_store.save_agent_skill_data(
80
+ agent_id, self.name, "rate_limit", new_rate_limit
81
+ )
82
+ return
83
+
84
+ async def fetch_price(
85
+ self, api_key: str, from_symbol: str, to_symbols: List[str]
86
+ ) -> dict:
87
+ """Fetch current price for a cryptocurrency in multiple currencies.
88
+
89
+ Args:
90
+ api_key: The CryptoCompare API key
91
+ from_symbol: Base cryptocurrency symbol to get prices for (e.g., 'BTC', 'ETH')
92
+ to_symbols: List of target currencies (fiat or crypto) (e.g., ['USD', 'EUR', 'JPY'])
93
+
94
+ Returns:
95
+ Dict containing the price data
96
+ """
97
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/price"
98
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
99
+
100
+ # Ensure from_symbol is a string, not a list
101
+ if isinstance(from_symbol, list):
102
+ from_symbol = from_symbol[0] if from_symbol else ""
103
+
104
+ # Ensure to_symbols is a list
105
+ if not isinstance(to_symbols, list):
106
+ to_symbols = [to_symbols] if to_symbols else ["USD"]
107
+
108
+ params = {
109
+ "fsym": from_symbol.upper(),
110
+ "tsyms": ",".join([s.upper() for s in to_symbols]),
111
+ }
112
+ async with httpx.AsyncClient() as client:
113
+ response = await client.get(url, params=params, headers=headers)
114
+ if response.status_code != 200:
115
+ logger.error(f"API returned status code {response.status_code}")
116
+ return {"error": f"API returned status code {response.status_code}"}
117
+ return response.json()
118
+
119
+ async def fetch_trading_signals(self, api_key: str, from_symbol: str) -> dict:
120
+ """Fetch the latest trading signals.
121
+
122
+ Args:
123
+ api_key: The CryptoCompare API key
124
+ from_symbol: Cryptocurrency symbol to fetch trading signals for (e.g., 'BTC')
125
+
126
+ Returns:
127
+ Dict containing the trading signals data
128
+ """
129
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/tradingsignals/intotheblock/latest"
130
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
131
+
132
+ # Ensure from_symbol is a string, not a list
133
+ if isinstance(from_symbol, list):
134
+ from_symbol = from_symbol[0] if from_symbol else ""
135
+
136
+ params = {"fsym": from_symbol.upper()}
137
+ async with httpx.AsyncClient() as client:
138
+ response = await client.get(url, params=params, headers=headers)
139
+ if response.status_code != 200:
140
+ logger.error(f"API returned status code {response.status_code}")
141
+ return {"error": f"API returned status code {response.status_code}"}
142
+ return response.json()
143
+
144
+ async def fetch_top_market_cap(
145
+ self, api_key: str, limit: int, to_symbol: str = "USD"
146
+ ) -> dict:
147
+ """Fetch top cryptocurrencies by market cap.
148
+
149
+ Args:
150
+ api_key: The CryptoCompare API key
151
+ limit: Number of cryptocurrencies to fetch
152
+ to_symbol: Quote currency for market cap calculation (e.g., 'USD', 'EUR')
153
+
154
+ Returns:
155
+ Dict containing the top market cap data
156
+ """
157
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/top/mktcapfull"
158
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
159
+
160
+ # Ensure to_symbol is a string, not a list
161
+ if isinstance(to_symbol, list):
162
+ to_symbol = to_symbol[0] if to_symbol else "USD"
163
+
164
+ params = {"limit": limit, "tsym": to_symbol.upper()}
165
+ async with httpx.AsyncClient() as client:
166
+ response = await client.get(url, params=params, headers=headers)
167
+ if response.status_code != 200:
168
+ logger.error(f"API returned status code {response.status_code}")
169
+ return {"error": f"API returned status code {response.status_code}"}
170
+ return response.json()
171
+
172
+ async def fetch_top_exchanges(
173
+ self, api_key: str, from_symbol: str, to_symbol: str = "USD"
174
+ ) -> dict:
175
+ """Fetch top exchanges for a cryptocurrency pair.
176
+
177
+ Args:
178
+ api_key: The CryptoCompare API key
179
+ from_symbol: Base cryptocurrency symbol for the trading pair (e.g., 'BTC')
180
+ to_symbol: Quote currency symbol for the trading pair. Defaults to 'USD'
181
+
182
+ Returns:
183
+ Dict containing the top exchanges data
184
+ """
185
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/top/exchanges"
186
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
187
+
188
+ # Ensure from_symbol and to_symbol are strings, not lists
189
+ if isinstance(from_symbol, list):
190
+ from_symbol = from_symbol[0] if from_symbol else ""
191
+ if isinstance(to_symbol, list):
192
+ to_symbol = to_symbol[0] if to_symbol else "USD"
193
+
194
+ params = {"fsym": from_symbol.upper(), "tsym": to_symbol.upper()}
195
+ async with httpx.AsyncClient() as client:
196
+ response = await client.get(url, params=params, headers=headers)
197
+ if response.status_code != 200:
198
+ logger.error(f"API returned status code {response.status_code}")
199
+ return {"error": f"API returned status code {response.status_code}"}
200
+ return response.json()
201
+
202
+ async def fetch_top_volume(
203
+ self, api_key: str, limit: int, to_symbol: str = "USD"
204
+ ) -> dict:
205
+ """Fetch top cryptocurrencies by total volume.
206
+
207
+ Args:
208
+ api_key: The CryptoCompare API key
209
+ limit: Number of cryptocurrencies to fetch
210
+ to_symbol: Quote currency for volume calculation. Defaults to 'USD'
211
+
212
+ Returns:
213
+ Dict containing the top volume data
214
+ """
215
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/top/totalvolfull"
216
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
217
+
218
+ # Ensure to_symbol is a string, not a list
219
+ if isinstance(to_symbol, list):
220
+ to_symbol = to_symbol[0] if to_symbol else "USD"
221
+
222
+ params = {"limit": limit, "tsym": to_symbol.upper()}
223
+ async with httpx.AsyncClient() as client:
224
+ response = await client.get(url, params=params, headers=headers)
225
+ if response.status_code != 200:
226
+ logger.error(f"API returned status code {response.status_code}")
227
+ return {"error": f"API returned status code {response.status_code}"}
228
+ return response.json()
229
+
230
+ async def fetch_news(self, api_key: str, token: str, timestamp: int = None) -> dict:
231
+ """Fetch news for a specific token and timestamp.
232
+
233
+ Args:
234
+ api_key: The CryptoCompare API key
235
+ token: Token symbol to fetch news for (e.g., BTC, ETH, SOL)
236
+ timestamp: Optional timestamp for fetching news
237
+
238
+ Returns:
239
+ Dict containing the news data
240
+ """
241
+ url = f"{CRYPTO_COMPARE_BASE_URL}/data/v2/news/"
242
+ headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
243
+
244
+ # Ensure token is a string, not a list
245
+ if isinstance(token, list):
246
+ token = token[0] if token else ""
247
+
248
+ params = {"categories": token.upper()}
249
+ if timestamp:
250
+ params["lTs"] = timestamp
251
+
252
+ async with httpx.AsyncClient() as client:
253
+ response = await client.get(url, params=params, headers=headers)
254
+ if response.status_code != 200:
255
+ logger.error(f"API returned status code {response.status_code}")
256
+ return {"error": f"API returned status code {response.status_code}"}
257
+ return response.json()
258
+
259
+
260
+ # Response Models
261
+ class CryptoPrice(BaseModel):
262
+ """Model representing a cryptocurrency price."""
263
+
264
+ from_symbol: str
265
+ to_symbol: str
266
+ price: float
267
+
268
+
269
+ class CryptoNews(BaseModel):
270
+ """Model representing a cryptocurrency news article."""
271
+
272
+ id: str
273
+ published_on: int
274
+ title: str
275
+ url: str
276
+ body: str
277
+ tags: str
278
+ categories: str
279
+ source: str
280
+ source_info: Dict[str, Any] = Field(default_factory=dict)
281
+
282
+
283
+ class CryptoExchange(BaseModel):
284
+ """Model representing a cryptocurrency exchange."""
285
+
286
+ exchange: str
287
+ from_symbol: str
288
+ to_symbol: str
289
+ volume24h: float
290
+ volume24h_to: float
291
+
292
+
293
+ class CryptoCurrency(BaseModel):
294
+ """Model representing a cryptocurrency."""
295
+
296
+ id: str
297
+ name: str
298
+ symbol: str
299
+ full_name: str
300
+ market_cap: float = 0
301
+ volume24h: float = 0
302
+ price: float = 0
303
+ change24h: float = 0
@@ -0,0 +1,96 @@
1
+ """Tool for fetching cryptocurrency news via CryptoCompare API."""
2
+
3
+ import logging
4
+ from typing import List, Type
5
+
6
+ from langchain_core.runnables import RunnableConfig
7
+ from pydantic import BaseModel, Field
8
+
9
+ from intentkit.skills.cryptocompare.base import CryptoCompareBaseTool, CryptoNews
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class CryptoCompareFetchNewsInput(BaseModel):
15
+ """Input for CryptoCompareFetchNews tool."""
16
+
17
+ token: str = Field(
18
+ ..., description="Token symbol to fetch news for (e.g., BTC, ETH, SOL)"
19
+ )
20
+
21
+
22
+ class CryptoCompareFetchNews(CryptoCompareBaseTool):
23
+ """Tool for fetching cryptocurrency news from CryptoCompare.
24
+
25
+ This tool uses the CryptoCompare API to retrieve the latest news articles
26
+ related to a specific cryptocurrency token.
27
+
28
+ Attributes:
29
+ name: The name of the tool.
30
+ description: A description of what the tool does.
31
+ args_schema: The schema for the tool's input arguments.
32
+ """
33
+
34
+ name: str = "cryptocompare_fetch_news"
35
+ description: str = "Fetch the latest cryptocurrency news for a specific token"
36
+ args_schema: Type[BaseModel] = CryptoCompareFetchNewsInput
37
+
38
+ async def _arun(
39
+ self,
40
+ token: str,
41
+ config: RunnableConfig,
42
+ **kwargs,
43
+ ) -> List[CryptoNews]:
44
+ """Async implementation of the tool to fetch cryptocurrency news.
45
+
46
+ Args:
47
+ token: Token symbol to fetch news for (e.g., BTC, ETH, SOL)
48
+ config: The configuration for the runnable, containing agent context.
49
+
50
+ Returns:
51
+ List[CryptoNews]: A list of cryptocurrency news articles.
52
+
53
+ Raises:
54
+ Exception: If there's an error accessing the CryptoCompare API.
55
+ """
56
+ try:
57
+ context = self.context_from_config(config)
58
+
59
+ # Check rate limit
60
+ await self.check_rate_limit(context.agent.id, max_requests=5, interval=60)
61
+
62
+ # Get API key from context
63
+ api_key = context.config.get("api_key")
64
+ if not api_key:
65
+ raise ValueError("CryptoCompare API key not found in configuration")
66
+
67
+ # Fetch news data directly
68
+ news_data = await self.fetch_news(api_key, token)
69
+
70
+ # Check for errors
71
+ if "error" in news_data:
72
+ raise ValueError(news_data["error"])
73
+
74
+ # Convert to list of CryptoNews objects
75
+ result = []
76
+ if "Data" in news_data and news_data["Data"]:
77
+ for article in news_data["Data"]:
78
+ result.append(
79
+ CryptoNews(
80
+ id=str(article["id"]),
81
+ published_on=article["published_on"],
82
+ title=article["title"],
83
+ url=article["url"],
84
+ body=article["body"],
85
+ tags=article.get("tags", ""),
86
+ categories=article.get("categories", ""),
87
+ source=article["source"],
88
+ source_info=article.get("source_info", {}),
89
+ )
90
+ )
91
+
92
+ return result
93
+
94
+ except Exception as e:
95
+ logger.error("Error fetching news: %s", str(e))
96
+ raise type(e)(f"[agent:{context.agent.id}]: {e}") from e