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
intentkit/clients/cdp.py CHANGED
@@ -1,179 +1,155 @@
1
- import json
1
+ import asyncio
2
2
  import logging
3
- from typing import Dict, Optional
4
-
5
- from bip32 import BIP32
6
- from cdp import CdpClient as OriginCdpClient
7
- from cdp import EvmServerAccount
8
- from coinbase_agentkit import (
9
- CdpEvmServerWalletProvider,
10
- CdpEvmServerWalletProviderConfig,
3
+
4
+ from cdp import CdpClient, EvmServerAccount # noqa: E402
5
+ from coinbase_agentkit import ( # noqa: E402
6
+ CdpEvmWalletProvider,
7
+ CdpEvmWalletProviderConfig,
11
8
  )
12
- from eth_keys.datatypes import PrivateKey
13
- from eth_utils import to_checksum_address
14
9
 
15
- from intentkit.abstracts.skill import SkillStoreABC
16
- from intentkit.models.agent import Agent
10
+ from intentkit.config.config import config
11
+ from intentkit.models.agent import Agent, AgentTable # noqa: E402
17
12
  from intentkit.models.agent_data import AgentData
13
+ from intentkit.models.db import get_session
14
+ from intentkit.utils.error import IntentKitAPIError # noqa: E402
18
15
 
19
- _clients: Dict[str, "CdpClient"] = {}
20
- _origin_cdp_client: Optional[OriginCdpClient] = None
16
+ _wallet_providers: dict[str, tuple[str, str, CdpEvmWalletProvider]] = {}
17
+ _cdp_client: CdpClient | None = None
21
18
 
22
19
  logger = logging.getLogger(__name__)
23
20
 
24
21
 
25
- def bip39_seed_to_eth_keys(seed_hex: str) -> Dict[str, str]:
26
- """
27
- Converts a BIP39 seed to an Ethereum private key, public key, and address.
22
+ def get_cdp_client() -> CdpClient:
23
+ global _cdp_client
24
+ if _cdp_client:
25
+ return _cdp_client
26
+
27
+ # Get credentials from global configuration
28
+ api_key_id = config.cdp_api_key_id
29
+ api_key_secret = config.cdp_api_key_secret
30
+ wallet_secret = config.cdp_wallet_secret
31
+
32
+ _cdp_client = CdpClient(
33
+ api_key_id=api_key_id,
34
+ api_key_secret=api_key_secret,
35
+ wallet_secret=wallet_secret,
36
+ )
37
+ return _cdp_client
28
38
 
29
- Args:
30
- seed_hex: The BIP39 seed in hexadecimal format
31
39
 
32
- Returns:
33
- Dict containing private_key, public_key, and address
34
- """
35
- # Convert the hex seed to bytes
36
- seed_bytes = bytes.fromhex(seed_hex)
40
+ def _assert_cdp_wallet_provider(agent: Agent) -> None:
41
+ if agent.wallet_provider != "cdp":
42
+ raise IntentKitAPIError(
43
+ 400,
44
+ "BadWalletProvider",
45
+ "Your agent wallet provider is not cdp but you selected a skill that requires a cdp wallet.",
46
+ )
47
+
48
+
49
+ async def _ensure_evm_account(
50
+ agent: Agent, agent_data: AgentData | None = None
51
+ ) -> tuple[EvmServerAccount, AgentData]:
52
+ cdp_client = get_cdp_client()
53
+ agent_data = agent_data or await AgentData.get(agent.id)
54
+ address = agent_data.evm_wallet_address
55
+ account: EvmServerAccount | None = None
56
+
57
+ if not address:
58
+ logger.info("Creating new wallet...")
59
+ account = await cdp_client.evm.create_account(
60
+ name=agent.id,
61
+ )
62
+ address = account.address
63
+ logger.info("Created new wallet: %s", address)
64
+
65
+ agent_data.evm_wallet_address = address
66
+ await agent_data.save()
67
+ if not agent.slug:
68
+ async with get_session() as db:
69
+ db_agent = await db.get(AgentTable, agent.id)
70
+ if db_agent and not db_agent.slug:
71
+ db_agent.slug = agent_data.evm_wallet_address
72
+ await db.commit()
37
73
 
38
- # Derive the master key from the seed
39
- bip32 = BIP32.from_seed(seed_bytes)
74
+ if account is None:
75
+ account = await cdp_client.evm.get_account(address=address)
40
76
 
41
- # Derive the Ethereum address using the standard derivation path
42
- private_key_bytes = bip32.get_privkey_from_path("m/44'/60'/0'/0/0")
77
+ return account, agent_data
43
78
 
44
- # Create a private key object
45
- private_key = PrivateKey(private_key_bytes)
46
79
 
47
- # Get the public key
48
- public_key = private_key.public_key
80
+ async def get_evm_account(agent: Agent) -> EvmServerAccount:
81
+ _assert_cdp_wallet_provider(agent)
82
+ account, _ = await _ensure_evm_account(agent)
83
+ return account
49
84
 
50
- # Get the Ethereum address
51
- address = public_key.to_address()
52
85
 
53
- return {
54
- "private_key": private_key.to_hex(),
55
- "public_key": public_key.to_hex(),
56
- "address": to_checksum_address(address),
86
+ def get_cdp_network(agent: Agent) -> str:
87
+ if not agent.network_id:
88
+ raise IntentKitAPIError(
89
+ 400,
90
+ "BadNetworkID",
91
+ "Your agent network ID is not set. Please set it in the agent config.",
92
+ )
93
+ mapping = {
94
+ "ethereum-mainnet": "ethereum",
95
+ "base-mainnet": "base",
96
+ "arbitrum-mainnet": "arbitrum",
97
+ "optimism-mainnet": "optimism",
98
+ "polygon-mainnet": "polygon",
99
+ "base-sepolia": "base-sepolia",
57
100
  }
101
+ if agent.network_id == "solana":
102
+ raise IntentKitAPIError(
103
+ 400, "BadNetworkID", "Solana is not supported by CDP EVM."
104
+ )
105
+ cdp_network = mapping.get(agent.network_id)
106
+ if not cdp_network:
107
+ raise IntentKitAPIError(
108
+ 400, "BadNetworkID", f"Unsupported network ID: {agent.network_id}"
109
+ )
110
+ return cdp_network
111
+
112
+
113
+ async def get_wallet_provider(agent: Agent) -> CdpEvmWalletProvider:
114
+ _assert_cdp_wallet_provider(agent)
115
+ if not agent.network_id:
116
+ raise IntentKitAPIError(
117
+ 400,
118
+ "BadNetworkID",
119
+ "Your agent network ID is not set. Please set it in the agent config.",
120
+ )
58
121
 
122
+ agent_data = await AgentData.get(agent.id)
123
+ address = agent_data.evm_wallet_address
59
124
 
60
- def get_origin_cdp_client(skill_store: SkillStoreABC) -> OriginCdpClient:
61
- global _origin_cdp_client
62
- if _origin_cdp_client:
63
- return _origin_cdp_client
125
+ cache_entry = _wallet_providers.get(agent.id)
126
+ if cache_entry:
127
+ cached_network_id, cached_address, provider = cache_entry
128
+ if cached_network_id == agent.network_id:
129
+ if not address:
130
+ address = cached_address or provider.get_address()
131
+ if cached_address == address:
132
+ return provider
133
+
134
+ account, agent_data = await _ensure_evm_account(agent, agent_data)
135
+ address = account.address
136
+
137
+ # Get credentials from global config
138
+ api_key_id = config.cdp_api_key_id
139
+ api_key_secret = config.cdp_api_key_secret
140
+ wallet_secret = config.cdp_wallet_secret
64
141
 
65
- # Get credentials from skill store system config
66
- api_key_id = skill_store.get_system_config("cdp_api_key_id")
67
- api_key_secret = skill_store.get_system_config("cdp_api_key_secret")
68
- wallet_secret = skill_store.get_system_config("cdp_wallet_secret")
142
+ network_id = agent.network_id
69
143
 
70
- _origin_cdp_client = OriginCdpClient(
144
+ wallet_provider_config = CdpEvmWalletProviderConfig(
71
145
  api_key_id=api_key_id,
72
146
  api_key_secret=api_key_secret,
147
+ network_id=network_id,
148
+ address=address,
73
149
  wallet_secret=wallet_secret,
74
150
  )
75
- return _origin_cdp_client
76
-
77
-
78
- class CdpClient:
79
- def __init__(self, agent_id: str, skill_store: SkillStoreABC) -> None:
80
- self._agent_id = agent_id
81
- self._skill_store = skill_store
82
- self._wallet_provider: Optional[CdpEvmServerWalletProvider] = None
83
- self._wallet_provider_config: Optional[CdpEvmServerWalletProviderConfig] = None
84
-
85
- async def get_wallet_provider(self) -> CdpEvmServerWalletProvider:
86
- if self._wallet_provider:
87
- return self._wallet_provider
88
- agent: Agent = await self._skill_store.get_agent_config(self._agent_id)
89
- agent_data: AgentData = await self._skill_store.get_agent_data(self._agent_id)
90
- network_id = agent.network_id
91
-
92
- # Get credentials from skill store system config
93
- api_key_id = self._skill_store.get_system_config("cdp_api_key_id")
94
- api_key_secret = self._skill_store.get_system_config("cdp_api_key_secret")
95
- wallet_secret = self._skill_store.get_system_config("cdp_wallet_secret")
96
-
97
- # already have address
98
- address = agent_data.evm_wallet_address
99
-
100
- # new agent or address not migrated yet
101
- if not address:
102
- # create cdp client for later use
103
- cdp_client = get_origin_cdp_client(self._skill_store)
104
- # try migrating from v1 cdp_wallet_data
105
- if agent_data.cdp_wallet_data:
106
- wallet_data = json.loads(agent_data.cdp_wallet_data)
107
- if not isinstance(wallet_data, dict):
108
- raise ValueError("Invalid wallet data format")
109
- if wallet_data.get("default_address_id") and wallet_data.get("seed"):
110
- # verify seed and convert to pk
111
- keys = bip39_seed_to_eth_keys(wallet_data["seed"])
112
- if keys["address"] != wallet_data["default_address_id"]:
113
- raise ValueError(
114
- "Bad wallet data, seed does not match default_address_id"
115
- )
116
- # try to import wallet to v2
117
- logger.info("Migrating wallet data to v2...")
118
- await cdp_client.evm.import_account(
119
- name=agent.id,
120
- private_key=keys["private_key"],
121
- )
122
- address = keys["address"]
123
- logger.info("Migrated wallet data to v2 successfully: %s", address)
124
- # still not address
125
- if not address:
126
- logger.info("Creating new wallet...")
127
- new_account = await cdp_client.evm.create_account(
128
- name=agent.id,
129
- )
130
- address = new_account.address
131
- logger.info("Created new wallet: %s", address)
132
-
133
- # do not close cached global client
134
- # now it should be created or migrated, store it
135
- agent_data.evm_wallet_address = address
136
- await agent_data.save()
137
-
138
- # it must have v2 account now, load agentkit wallet provider
139
- self._wallet_provider_config = CdpEvmServerWalletProviderConfig(
140
- api_key_id=api_key_id,
141
- api_key_secret=api_key_secret,
142
- network_id=network_id,
143
- address=address,
144
- wallet_secret=wallet_secret,
145
- )
146
- self._wallet_provider = CdpEvmServerWalletProvider(self._wallet_provider_config)
147
- # hack for cdp bug
148
- if network_id == "base-mainnet":
149
- self._wallet_provider._network.network_id = "base"
150
- elif network_id == "arbitrum-mainnet":
151
- self._wallet_provider._network.network_id = "arbitrum"
152
- elif network_id == "optimism-mainnet":
153
- self._wallet_provider._network.network_id = "optimism"
154
- elif network_id == "polygon-mainnet":
155
- self._wallet_provider._network.network_id = "polygon"
156
- elif network_id == "ethereum-mainnet":
157
- self._wallet_provider._network.network_id = "ethereum"
158
- return self._wallet_provider
159
-
160
- async def get_account(self) -> EvmServerAccount:
161
- """Get the account object from the wallet provider.
162
-
163
- Returns:
164
- EvmServerAccount: The account object that can be used for balance checks, transfers, etc.
165
- """
166
- wallet_provider = await self.get_wallet_provider()
167
- # Access the internal account object
168
- return wallet_provider._account
169
-
170
- async def get_provider_config(self) -> CdpEvmServerWalletProviderConfig:
171
- if not self._wallet_provider_config:
172
- await self.get_wallet_provider()
173
- return self._wallet_provider_config
174
-
175
-
176
- async def get_cdp_client(agent_id: str, skill_store: SkillStoreABC) -> "CdpClient":
177
- if agent_id not in _clients:
178
- _clients[agent_id] = CdpClient(agent_id, skill_store)
179
- return _clients[agent_id]
151
+ wallet_provider = await asyncio.to_thread(
152
+ CdpEvmWalletProvider, wallet_provider_config
153
+ )
154
+ _wallet_providers[agent.id] = (network_id, address, wallet_provider)
155
+ return wallet_provider
@@ -5,7 +5,7 @@ S3 utility module for storing and retrieving images from AWS S3.
5
5
  import logging
6
6
  from enum import Enum
7
7
  from io import BytesIO
8
- from typing import Optional
8
+ from typing import cast
9
9
 
10
10
  import boto3
11
11
  import filetype
@@ -13,40 +13,58 @@ import httpx
13
13
  from botocore.exceptions import ClientError
14
14
  from mypy_boto3_s3.client import S3Client
15
15
 
16
+ from intentkit.config.config import config
17
+
16
18
  logger = logging.getLogger(__name__)
17
19
 
18
20
  # Global variables for S3 configuration
19
- _bucket: Optional[str] = None
20
- _client: Optional[S3Client] = None
21
- _prefix: Optional[str] = None
22
- _cdn_url: Optional[str] = None
21
+ _bucket: str | None = None
22
+ _client: S3Client | None = None
23
+ _prefix: str | None = None
24
+ _cdn_url: str | None = None
23
25
 
24
26
 
25
- def init_s3(bucket: str, cdn_url: str, env: str) -> None:
27
+ def get_s3_client() -> S3Client | None:
26
28
  """
27
- Initialize S3 configuration.
28
-
29
- Args:
30
- bucket: S3 bucket name
31
- cdn_url: CDN URL for the S3 bucket
32
- env: Environment name for the prefix
33
-
34
- Raises:
35
- ValueError: If bucket or cdn_url is empty
29
+ Get or initialize S3 client and configuration.
30
+ Returns None if configuration is missing.
36
31
  """
37
32
  global _bucket, _client, _prefix, _cdn_url
38
33
 
39
- if not bucket:
40
- raise ValueError("S3 bucket name cannot be empty")
41
- if not cdn_url:
42
- raise ValueError("S3 CDN URL cannot be empty")
34
+ if _client is not None:
35
+ return _client
36
+
37
+ if not config.aws_s3_bucket or not config.aws_s3_cdn_url:
38
+ # Only log once or if needed, but here we just return None
39
+ # The calling functions usually log "S3 not initialized"
40
+ return None
43
41
 
44
- _bucket = bucket
45
- _cdn_url = cdn_url
46
- _prefix = f"{env}/intentkit/"
47
- _client = boto3.client("s3")
42
+ _bucket = config.aws_s3_bucket
43
+ _cdn_url = config.aws_s3_cdn_url
44
+ _prefix = f"{config.env}/intentkit/"
48
45
 
49
- logger.info(f"S3 initialized with bucket: {bucket}, prefix: {_prefix}")
46
+ try:
47
+ if config.aws_s3_endpoint_url:
48
+ _client = cast(
49
+ S3Client,
50
+ boto3.client(
51
+ "s3",
52
+ endpoint_url=config.aws_s3_endpoint_url,
53
+ region_name=config.aws_s3_region_name,
54
+ aws_access_key_id=config.aws_s3_access_key_id,
55
+ aws_secret_access_key=config.aws_s3_secret_access_key,
56
+ ),
57
+ )
58
+ logger.info(
59
+ f"S3 initialized with custom endpoint: {config.aws_s3_endpoint_url}, bucket: {_bucket}, prefix: {_prefix}"
60
+ )
61
+ else:
62
+ _client = cast(S3Client, boto3.client("s3"))
63
+ logger.info(f"S3 initialized with bucket: {_bucket}, prefix: {_prefix}")
64
+ return _client
65
+ except Exception as e:
66
+ logger.error(f"Failed to initialize S3 client: {e}")
67
+ return None
50
68
 
51
69
 
52
70
  async def store_image(url: str, key: str) -> str:
@@ -64,15 +82,16 @@ async def store_image(url: str, key: str) -> str:
64
82
  ClientError: If the upload fails
65
83
  httpx.HTTPError: If the download fails
66
84
  """
67
- if not _client or not _bucket or not _prefix or not _cdn_url:
85
+ client = get_s3_client()
86
+ if not client or not _bucket or not _prefix or not _cdn_url:
68
87
  # If S3 is not initialized, log and return the original URL
69
88
  logger.info("S3 not initialized. Returning original URL.")
70
89
  return url
71
90
 
72
91
  try:
73
92
  # Download the image from the URL asynchronously
74
- async with httpx.AsyncClient() as client:
75
- response = await client.get(url, follow_redirects=True)
93
+ async with httpx.AsyncClient() as http_client:
94
+ response = await http_client.get(url, follow_redirects=True)
76
95
  response.raise_for_status()
77
96
 
78
97
  # Prepare the S3 key with prefix
@@ -93,7 +112,7 @@ async def store_image(url: str, key: str) -> str:
93
112
  content_type = "image/jpeg"
94
113
 
95
114
  # Upload to S3
96
- _client.upload_fileobj(
115
+ client.upload_fileobj(
97
116
  file_obj,
98
117
  _bucket,
99
118
  prefixed_key,
@@ -114,7 +133,7 @@ async def store_image(url: str, key: str) -> str:
114
133
 
115
134
 
116
135
  async def store_image_bytes(
117
- image_bytes: bytes, key: str, content_type: Optional[str] = None
136
+ image_bytes: bytes, key: str, content_type: str | None = None
118
137
  ) -> str:
119
138
  """
120
139
  Store raw image bytes to S3.
@@ -131,7 +150,8 @@ async def store_image_bytes(
131
150
  ClientError: If the upload fails
132
151
  ValueError: If S3 is not initialized or image_bytes is empty
133
152
  """
134
- if not _client or not _bucket or not _prefix or not _cdn_url:
153
+ client = get_s3_client()
154
+ if not client or not _bucket or not _prefix or not _cdn_url:
135
155
  # If S3 is not initialized, log and return empty string
136
156
  logger.info("S3 not initialized. Cannot store image bytes.")
137
157
  return ""
@@ -158,7 +178,7 @@ async def store_image_bytes(
158
178
 
159
179
  logger.info("uploading image to s3")
160
180
  # Upload to S3
161
- _client.upload_fileobj(
181
+ client.upload_fileobj(
162
182
  file_obj,
163
183
  _bucket,
164
184
  prefixed_key,
@@ -182,11 +202,65 @@ class FileType(str, Enum):
182
202
  PDF = "pdf"
183
203
 
184
204
 
205
+ async def store_file(
206
+ content: bytes,
207
+ key: str,
208
+ content_type: str | None = None,
209
+ size: int | None = None,
210
+ ) -> str:
211
+ """Store raw file bytes with automatic content type detection."""
212
+ client = get_s3_client()
213
+ if not client or not _bucket or not _prefix or not _cdn_url:
214
+ logger.info("S3 not initialized. Cannot store file bytes.")
215
+ return ""
216
+
217
+ if not content:
218
+ raise ValueError("File content cannot be empty")
219
+
220
+ actual_size = len(content)
221
+ if size is not None and size != actual_size:
222
+ raise ValueError(
223
+ f"Provided size {size} does not match actual content size {actual_size} bytes"
224
+ )
225
+
226
+ effective_size = size if size is not None else actual_size
227
+
228
+ detected_content_type = content_type
229
+ if not detected_content_type:
230
+ kind = filetype.guess(content)
231
+ detected_content_type = (
232
+ kind.mime if kind and kind.mime else "application/octet-stream"
233
+ )
234
+
235
+ prefixed_key = f"{_prefix}{key}"
236
+ file_obj = BytesIO(content)
237
+
238
+ logger.info(
239
+ "Uploading file to S3 with content type %s and size %s bytes",
240
+ detected_content_type,
241
+ effective_size,
242
+ )
243
+
244
+ client.upload_fileobj(
245
+ file_obj,
246
+ _bucket,
247
+ prefixed_key,
248
+ ExtraArgs={
249
+ "ContentType": detected_content_type,
250
+ "ContentDisposition": "inline",
251
+ },
252
+ )
253
+
254
+ cdn_url = f"{_cdn_url}/{prefixed_key}"
255
+ logger.info("File uploaded successfully to %s", cdn_url)
256
+ return cdn_url
257
+
258
+
185
259
  async def store_file_bytes(
186
260
  file_bytes: bytes,
187
261
  key: str,
188
262
  file_type: FileType,
189
- size_limit_bytes: Optional[int] = None,
263
+ size_limit_bytes: int | None = None,
190
264
  ) -> str:
191
265
  """
192
266
  Store raw file bytes (image, video, sound, pdf) to S3.
@@ -204,7 +278,8 @@ async def store_file_bytes(
204
278
  ClientError: If the upload fails
205
279
  ValueError: If S3 is not initialized, file_bytes is empty, or file exceeds size limit
206
280
  """
207
- if not _client or not _bucket or not _prefix or not _cdn_url:
281
+ client = get_s3_client()
282
+ if not client or not _bucket or not _prefix or not _cdn_url:
208
283
  logger.info("S3 not initialized. Cannot store file bytes.")
209
284
  return ""
210
285
  if not file_bytes:
@@ -250,7 +325,7 @@ async def store_file_bytes(
250
325
  logger.info(f"Uploading {file_type} to S3 with content type {content_type}")
251
326
 
252
327
  # Upload to S3
253
- _client.upload_fileobj(
328
+ client.upload_fileobj(
254
329
  file_obj,
255
330
  _bucket,
256
331
  prefixed_key,