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
@@ -0,0 +1,231 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from collections.abc import Sequence
5
+ from typing import Any
6
+
7
+ from langchain.agents.middleware import AgentMiddleware
8
+ from langchain.agents.middleware.summarization import SummarizationMiddleware
9
+ from langchain_core.messages import (
10
+ AIMessage,
11
+ BaseMessage,
12
+ RemoveMessage,
13
+ ToolMessage,
14
+ )
15
+ from langchain_core.messages.utils import count_tokens_approximately, trim_messages
16
+ from langchain_core.tools import BaseTool
17
+ from langgraph.graph.message import REMOVE_ALL_MESSAGES
18
+ from langgraph.runtime import Runtime
19
+ from langgraph.types import StreamWriter
20
+
21
+ from intentkit.abstracts.graph import AgentContext, AgentError, AgentState
22
+ from intentkit.core.credit import skill_cost
23
+ from intentkit.core.prompt import build_system_prompt
24
+ from intentkit.models.credit import CreditAccount, OwnerType
25
+ from intentkit.models.llm import LLMModelInfo, LLMProvider
26
+ from intentkit.models.skill import Skill
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ def _validate_chat_history(messages: Sequence[BaseMessage]) -> None:
32
+ """Validate that all tool calls in AIMessages have a corresponding ToolMessage."""
33
+
34
+ all_tool_calls = [
35
+ tool_call
36
+ for message in messages
37
+ if isinstance(message, AIMessage)
38
+ for tool_call in message.tool_calls
39
+ ]
40
+ tool_call_ids_with_results = {
41
+ message.tool_call_id for message in messages if isinstance(message, ToolMessage)
42
+ }
43
+ tool_calls_without_results = [
44
+ tool_call
45
+ for tool_call in all_tool_calls
46
+ if tool_call["id"] not in tool_call_ids_with_results
47
+ ]
48
+ if not tool_calls_without_results:
49
+ return
50
+
51
+ message = (
52
+ "Found AIMessages with tool_calls that do not have a corresponding ToolMessage. "
53
+ f"Here are the first few of those tool calls: {tool_calls_without_results[:3]}"
54
+ )
55
+ raise ValueError(message)
56
+
57
+
58
+ class TrimMessagesMiddleware(AgentMiddleware[AgentState, AgentContext]):
59
+ """Middleware that trims conversation history before invoking the model."""
60
+
61
+ def __init__(self, *, max_summary_tokens: int) -> None:
62
+ super().__init__()
63
+ self.max_summary_tokens = max_summary_tokens
64
+
65
+ async def abefore_model(
66
+ self, state: AgentState, runtime: Runtime[AgentContext]
67
+ ) -> dict[str, Any]:
68
+ del runtime
69
+ messages = state.get("messages")
70
+ context = state.get("context", {})
71
+ if messages is None or not isinstance(messages, list) or len(messages) == 0:
72
+ raise ValueError("Missing required field `messages` in the input.")
73
+ try:
74
+ _validate_chat_history(messages)
75
+ except ValueError as e:
76
+ logger.error(f"Invalid chat history: {e}")
77
+ logger.info(state)
78
+ return {"messages": [RemoveMessage(REMOVE_ALL_MESSAGES)]}
79
+
80
+ trimmed_messages = trim_messages(
81
+ messages,
82
+ strategy="last",
83
+ token_counter=count_tokens_approximately,
84
+ max_tokens=self.max_summary_tokens,
85
+ start_on="human",
86
+ end_on=("human", "tool"),
87
+ )
88
+ if len(trimmed_messages) < len(messages):
89
+ logger.info(f"Trimmed messages: {len(messages)} -> {len(trimmed_messages)}")
90
+ if len(trimmed_messages) <= 3:
91
+ logger.info(f"Too few messages after trim: {len(trimmed_messages)}")
92
+ return {}
93
+ return {
94
+ "messages": [RemoveMessage(REMOVE_ALL_MESSAGES)] + trimmed_messages,
95
+ "context": context,
96
+ }
97
+ return {}
98
+
99
+
100
+ class DynamicPromptMiddleware(AgentMiddleware[AgentState, AgentContext]):
101
+ """Middleware that builds the system prompt dynamically per request."""
102
+
103
+ def __init__(self, agent, agent_data) -> None:
104
+ super().__init__()
105
+ self.agent = agent
106
+ self.agent_data = agent_data
107
+
108
+ async def awrap_model_call(self, request, handler): # type: ignore[override]
109
+ context = request.runtime.context
110
+ system_prompt = await build_system_prompt(self.agent, self.agent_data, context)
111
+ updated_request = request.override(system_prompt=system_prompt)
112
+ return await handler(updated_request)
113
+
114
+
115
+ class ToolBindingMiddleware(AgentMiddleware[AgentState, AgentContext]):
116
+ """Middleware that selects tools and model parameters based on context."""
117
+
118
+ def __init__(
119
+ self,
120
+ llm_model: LLMModelInfo,
121
+ public_tools: list[BaseTool | dict],
122
+ private_tools: list[BaseTool | dict],
123
+ ) -> None:
124
+ super().__init__()
125
+ self.llm_model = llm_model
126
+ self.public_tools = public_tools
127
+ self.private_tools = private_tools
128
+
129
+ async def awrap_model_call(self, request, handler): # type: ignore[override]
130
+ context = request.runtime.context
131
+
132
+ llm_params: dict[str, Any] = {}
133
+ tools: list[BaseTool | dict] = (
134
+ self.private_tools if context.is_private else self.public_tools
135
+ )
136
+ tools = list(
137
+ {
138
+ tool.name if isinstance(tool, BaseTool) else str(tool): tool
139
+ for tool in tools
140
+ }.values()
141
+ )
142
+
143
+ if context.search or context.agent.has_search():
144
+ if self.llm_model.info.supports_search:
145
+ tools.append({"type": "web_search"})
146
+ if (
147
+ self.llm_model.info.provider == LLMProvider.OPENAI
148
+ and self.llm_model.model_name == "gpt-5-mini"
149
+ ):
150
+ llm_params["reasoning_effort"] = "medium"
151
+ if self.llm_model.info.provider == LLMProvider.XAI:
152
+ llm_params["search_parameters"] = {"mode": "auto"}
153
+ else:
154
+ logger.debug(
155
+ "Search requested but model does not support native search"
156
+ )
157
+
158
+ model = await self.llm_model.create_instance(llm_params)
159
+ updated_request = request.override(
160
+ model=model,
161
+ tools=tools,
162
+ model_settings=llm_params,
163
+ )
164
+ return await handler(updated_request)
165
+
166
+
167
+ class CreditCheckMiddleware(AgentMiddleware[AgentState, AgentContext]):
168
+ """Middleware that validates tool affordability before execution."""
169
+
170
+ def __init__(self) -> None:
171
+ super().__init__()
172
+ self.func_accepts_config = True
173
+
174
+ async def aafter_model(
175
+ self,
176
+ state: AgentState,
177
+ runtime: Runtime[AgentContext],
178
+ *,
179
+ writer: StreamWriter | None = None,
180
+ ) -> dict[str, Any]:
181
+ context = runtime.context
182
+ messages = state.get("messages")
183
+ if messages is None or not isinstance(messages, list) or len(messages) == 0:
184
+ raise ValueError("Missing required field `messages` in the input.")
185
+
186
+ payer = context.payer
187
+ if not payer:
188
+ return {}
189
+
190
+ msg = messages[-1]
191
+ agent = context.agent
192
+ account = await CreditAccount.get_or_create(OwnerType.USER, payer)
193
+ if hasattr(msg, "tool_calls") and msg.tool_calls:
194
+ for tool_call in msg.tool_calls:
195
+ skill_meta = await Skill.get(tool_call.get("name"))
196
+ if not skill_meta:
197
+ continue
198
+ skill_cost_info = await skill_cost(skill_meta.name, payer, agent)
199
+ total_paid = skill_cost_info.total_amount
200
+ if not account.has_sufficient_credits(total_paid):
201
+ error_message = (
202
+ "Insufficient credits. Please top up your account. "
203
+ f"You need {total_paid} credits, but you only have {account.balance} credits."
204
+ )
205
+ state_update: dict[str, Any] = {
206
+ "error": AgentError.INSUFFICIENT_CREDITS,
207
+ "messages": [
208
+ RemoveMessage(id=msg.id),
209
+ AIMessage(content=error_message),
210
+ ],
211
+ }
212
+ if writer:
213
+ writer(
214
+ {
215
+ "credit_check": {
216
+ "error": AgentError.INSUFFICIENT_CREDITS,
217
+ "message": error_message,
218
+ }
219
+ }
220
+ )
221
+ return state_update
222
+ return {}
223
+
224
+
225
+ __all__ = [
226
+ "CreditCheckMiddleware",
227
+ "DynamicPromptMiddleware",
228
+ "SummarizationMiddleware",
229
+ "ToolBindingMiddleware",
230
+ "TrimMessagesMiddleware",
231
+ ]
intentkit/core/prompt.py CHANGED
@@ -1,17 +1,14 @@
1
1
  import re
2
- from typing import Callable, Optional
3
2
 
4
3
  from eth_utils import is_address
5
- from langchain_core.messages import BaseMessage
6
- from langchain_core.prompts import ChatPromptTemplate
7
- from langgraph.runtime import Runtime
8
4
 
9
- from intentkit.abstracts.graph import AgentContext, AgentState
5
+ from intentkit.abstracts.graph import AgentContext
10
6
  from intentkit.config.config import config
11
7
  from intentkit.models.agent import Agent
12
8
  from intentkit.models.agent_data import AgentData
13
9
  from intentkit.models.chat import AuthorType
14
10
  from intentkit.models.skill import Skill
11
+ from intentkit.models.user import User
15
12
 
16
13
  # ============================================================================
17
14
  # CONSTANTS AND CONFIGURATION
@@ -34,7 +31,6 @@ user confirmation before broadcasting any approval transactions for security rea
34
31
 
35
32
  """
36
33
 
37
-
38
34
  # ============================================================================
39
35
  # CORE PROMPT BUILDING FUNCTIONS
40
36
  # ============================================================================
@@ -110,28 +106,66 @@ def _build_wallet_section(agent: Agent, agent_data: AgentData) -> str:
110
106
 
111
107
  if agent_data.evm_wallet_address and network_id != "solana":
112
108
  wallet_parts.append(
113
- f"Your wallet address in {network_id} is {agent_data.evm_wallet_address}."
109
+ f"Your EVM wallet address is {agent_data.evm_wallet_address}."
110
+ f"You are now in {network_id} network."
114
111
  )
115
112
  if agent_data.solana_wallet_address and network_id == "solana":
116
113
  wallet_parts.append(
117
- f"Your wallet address in {network_id} is {agent_data.solana_wallet_address}."
114
+ f"Your Solana wallet address is {agent_data.solana_wallet_address}."
115
+ f"You are now in {network_id} network."
118
116
  )
119
117
 
118
+ # Add CDP skills prompt if CDP skills are enabled
119
+ if agent.skills and "cdp" in agent.skills:
120
+ cdp_config = agent.skills["cdp"]
121
+ if cdp_config and cdp_config.get("enabled") is True:
122
+ # Check if any CDP skills are in public or private state (not disabled)
123
+ states = cdp_config.get("states", {})
124
+ has_enabled_cdp_skills = any(
125
+ state in ["public", "private"] for state in states.values()
126
+ )
127
+ if has_enabled_cdp_skills:
128
+ wallet_parts.append(
129
+ "If a skill input parameter requires a token address but you only have the user-provided token symbol, "
130
+ "and the address cannot be found in the nearby context, you must use the `token_search` skill to query "
131
+ f"the address of that symbol on the current chain ({network_id}) and confirm this address with the user."
132
+ "If the `token_search` skill is not found, remind the user to enable it."
133
+ )
134
+
120
135
  return "\n".join(wallet_parts) + ("\n" if wallet_parts else "")
121
136
 
122
137
 
123
- def _build_user_info_section(context: AgentContext) -> str:
138
+ async def _build_user_info_section(context: AgentContext) -> str:
124
139
  """Build user information section when user_id is a valid EVM wallet address."""
125
140
  if not context.user_id:
126
141
  return ""
127
142
 
128
- # Check if user_id is a valid EVM wallet address
129
- try:
130
- if is_address(context.user_id):
131
- return f"## User Info\n\nThe person you are talking to has wallet address: {context.user_id}\n\n"
132
- except Exception:
133
- # If validation fails, don't include the section
134
- pass
143
+ user = await User.get(context.user_id)
144
+
145
+ prompt_array = []
146
+
147
+ evm_wallet_address = ""
148
+ if user and user.evm_wallet_address:
149
+ evm_wallet_address = user.evm_wallet_address
150
+ elif is_address(context.user_id):
151
+ evm_wallet_address = context.user_id
152
+
153
+ if evm_wallet_address:
154
+ prompt_array.append(
155
+ f"The user you are talking to has EVM wallet address: {evm_wallet_address}\n"
156
+ )
157
+
158
+ if user:
159
+ if user.email:
160
+ prompt_array.append(f"User Email: {user.email}\n")
161
+ if user.x_username:
162
+ prompt_array.append(f"User X Username: {user.x_username}\n")
163
+ if user.telegram_username:
164
+ prompt_array.append(f"User Telegram Username: {user.telegram_username}\n")
165
+
166
+ if prompt_array:
167
+ prompt_array.append("\n")
168
+ return "## User Info\n\n" + "".join(prompt_array)
135
169
 
136
170
  return ""
137
171
 
@@ -202,36 +236,19 @@ def agent_prompt(agent: Agent, agent_data: AgentData) -> str:
202
236
 
203
237
 
204
238
  async def explain_prompt(message: str) -> str:
205
- """
206
- Process message to replace @skill:*:* patterns with (call skill xxxxx) format.
207
- This function is used when admin_llm_skill_control is enabled.
208
-
209
- Args:
210
- message (str): The input message to process
211
-
212
- Returns:
213
- str: The processed message with @skill patterns replaced
214
- """
215
- # Pattern to match @skill:category:config_name with word boundaries
216
- pattern = r"\b@skill:([^:]+):([^\s]+)\b"
239
+ pattern = r"@skill:([^:]+):([^\s]+)\b"
217
240
 
218
241
  async def replace_skill_pattern(match):
219
242
  category = match.group(1)
220
243
  config_name = match.group(2)
221
244
 
222
- # Get skill by category and config_name
223
245
  skill = await Skill.get_by_config_name(category, config_name)
224
-
225
246
  if skill:
226
247
  return f"(call skill {skill.name})"
227
248
  else:
228
- # If skill not found, keep original pattern
229
249
  return match.group(0)
230
250
 
231
- # Find all matches
232
251
  matches = list(re.finditer(pattern, message))
233
-
234
- # Process matches in reverse order to maintain string positions
235
252
  result = message
236
253
  for match in reversed(matches):
237
254
  replacement = await replace_skill_pattern(match)
@@ -290,7 +307,7 @@ def _build_autonomous_task_prompt(agent: Agent, context: AgentContext) -> str:
290
307
  return f"{task_info}. "
291
308
 
292
309
 
293
- async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> Optional[str]:
310
+ async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> str | None:
294
311
  """
295
312
  Build entrypoint-specific prompt based on context.
296
313
 
@@ -303,7 +320,7 @@ async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> Option
303
320
  context: The agent context containing entrypoint information
304
321
 
305
322
  Returns:
306
- Optional[str]: The entrypoint-specific prompt, or None if no entrypoint
323
+ str | None: The entrypoint-specific prompt, or None if no entrypoint
307
324
  """
308
325
  if not context.entrypoint:
309
326
  return None
@@ -325,10 +342,6 @@ async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> Option
325
342
  elif entrypoint == AuthorType.TRIGGER.value:
326
343
  entrypoint_prompt = "\n\n" + _build_autonomous_task_prompt(agent, context)
327
344
 
328
- # Process with admin LLM skill control if enabled
329
- if entrypoint_prompt and config.admin_llm_skill_control:
330
- entrypoint_prompt = await explain_prompt(entrypoint_prompt)
331
-
332
345
  return entrypoint_prompt
333
346
 
334
347
 
@@ -348,83 +361,30 @@ def build_internal_info_prompt(context: AgentContext) -> str:
348
361
  # ============================================================================
349
362
 
350
363
 
351
- def create_formatted_prompt_function(agent: Agent, agent_data: AgentData) -> Callable:
352
- """
353
- Create the formatted_prompt function with agent-specific configuration.
364
+ async def build_system_prompt(
365
+ agent: Agent, agent_data: AgentData, context: AgentContext
366
+ ) -> str:
367
+ """Construct the final system prompt for an agent run."""
354
368
 
355
- This is the main factory function that creates a prompt formatting function
356
- tailored to a specific agent. The returned function will be used by the
357
- agent's runtime to format prompts for each conversation.
369
+ base_prompt = build_agent_prompt(agent, agent_data)
370
+ final_system_prompt = await explain_prompt(escape_prompt(base_prompt))
358
371
 
359
- Args:
360
- agent: The agent configuration
361
- agent_data: The agent's runtime data
362
-
363
- Returns:
364
- Callable: An async function that formats prompts based on agent state and context
365
- """
366
- # Build base prompt using the new function name
367
- prompt = build_agent_prompt(agent, agent_data)
368
- escaped_prompt = escape_prompt(prompt)
369
-
370
- # Process with admin LLM skill control if enabled
371
- async def get_base_prompt():
372
- if config.admin_llm_skill_control:
373
- return await explain_prompt(escaped_prompt)
374
- return escaped_prompt
375
-
376
- # Build prompt array
377
- prompt_array = [
378
- ("placeholder", "{system_prompt}"),
379
- ("placeholder", "{messages}"),
380
- ]
381
-
382
- if agent.prompt_append:
383
- # Escape any curly braces in prompt_append
384
- escaped_append = escape_prompt(agent.prompt_append)
385
- prompt_array.append(("system", escaped_append))
386
-
387
- prompt_temp = ChatPromptTemplate.from_messages(prompt_array)
388
-
389
- async def formatted_prompt(
390
- state: AgentState, runtime: Runtime[AgentContext]
391
- ) -> list[BaseMessage]:
392
- # Get base prompt (with potential admin LLM skill control processing)
393
- final_system_prompt = await get_base_prompt()
372
+ entrypoint_prompt = await build_entrypoint_prompt(agent, context)
373
+ if entrypoint_prompt:
374
+ processed_entrypoint = await explain_prompt(entrypoint_prompt)
375
+ final_system_prompt = (
376
+ f"{final_system_prompt}## Entrypoint rules{processed_entrypoint}\n\n"
377
+ )
394
378
 
395
- context = runtime.context
379
+ user_info = await _build_user_info_section(context)
380
+ if user_info:
381
+ final_system_prompt = f"{final_system_prompt}{user_info}"
396
382
 
397
- # Add entrypoint prompt if applicable
398
- entrypoint_prompt = await build_entrypoint_prompt(agent, context)
399
- if entrypoint_prompt:
400
- final_system_prompt = (
401
- f"{final_system_prompt}## Entrypoint rules{entrypoint_prompt}\n\n"
402
- )
383
+ internal_info = build_internal_info_prompt(context)
384
+ final_system_prompt = f"{final_system_prompt}{internal_info}"
403
385
 
404
- # Add user info if user_id is a valid EVM wallet address
405
- user_info = _build_user_info_section(context)
406
- if user_info:
407
- final_system_prompt = f"{final_system_prompt}{user_info}"
408
-
409
- # Add internal info
410
- internal_info = build_internal_info_prompt(context)
411
- final_system_prompt = f"{final_system_prompt}{internal_info}"
412
-
413
- # Process prompt_append with admin LLM skill control if needed
414
- if agent.prompt_append and config.admin_llm_skill_control:
415
- # Find the system message in prompt_array and process it
416
- for i, (role, content) in enumerate(prompt_array):
417
- if role == "system":
418
- processed_append = await explain_prompt(content)
419
- prompt_array[i] = ("system", processed_append)
420
- break
421
-
422
- system_prompt = [("system", final_system_prompt)]
423
- return prompt_temp.invoke(
424
- {
425
- "messages": state["messages"],
426
- "system_prompt": system_prompt,
427
- }
428
- )
386
+ if agent.prompt_append:
387
+ processed_append = await explain_prompt(agent.prompt_append)
388
+ final_system_prompt = f"{final_system_prompt}{processed_append}"
429
389
 
430
- return formatted_prompt
390
+ return final_system_prompt
@@ -0,0 +1,143 @@
1
+ """Core scheduler utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping, MutableMapping
6
+
7
+ from apscheduler.jobstores.base import BaseJobStore
8
+ from apscheduler.schedulers.asyncio import AsyncIOScheduler
9
+ from apscheduler.triggers.cron import CronTrigger
10
+
11
+ from intentkit.core.agent import (
12
+ update_agent_action_cost,
13
+ update_agents_account_snapshot,
14
+ update_agents_statistics,
15
+ )
16
+ from intentkit.core.credit import refill_all_free_credits
17
+ from intentkit.models.agent_data import AgentQuota
18
+
19
+
20
+ def create_scheduler(
21
+ jobstores: Mapping[str, BaseJobStore]
22
+ | MutableMapping[str, BaseJobStore]
23
+ | None = None,
24
+ ) -> AsyncIOScheduler:
25
+ """Create and configure the APScheduler with all periodic tasks."""
26
+ scheduler = AsyncIOScheduler(jobstores=dict(jobstores or {}))
27
+
28
+ # Reset daily quotas at UTC 00:00
29
+ scheduler.add_job(
30
+ AgentQuota.reset_daily_quotas,
31
+ trigger=CronTrigger(hour=0, minute=0, timezone="UTC"),
32
+ id="reset_daily_quotas",
33
+ name="Reset daily quotas",
34
+ replace_existing=True,
35
+ )
36
+
37
+ # Reset monthly quotas at UTC 00:00 on the first day of each month
38
+ scheduler.add_job(
39
+ AgentQuota.reset_monthly_quotas,
40
+ trigger=CronTrigger(day=1, hour=0, minute=0, timezone="UTC"),
41
+ id="reset_monthly_quotas",
42
+ name="Reset monthly quotas",
43
+ replace_existing=True,
44
+ )
45
+
46
+ # Refill free credits every hour at minute 20
47
+ scheduler.add_job(
48
+ refill_all_free_credits,
49
+ trigger=CronTrigger(minute="20", timezone="UTC"),
50
+ id="refill_free_credits",
51
+ name="Refill free credits",
52
+ replace_existing=True,
53
+ )
54
+
55
+ # Update agent account snapshots hourly
56
+ scheduler.add_job(
57
+ update_agents_account_snapshot,
58
+ trigger=CronTrigger(minute=0, timezone="UTC"),
59
+ id="update_agent_account_snapshot",
60
+ name="Update agent account snapshots",
61
+ replace_existing=True,
62
+ )
63
+
64
+ # Update agent assets daily at UTC midnight
65
+ # This is too expensive to run daily, so it will only be triggered when detail page is visited
66
+ # scheduler.add_job(
67
+ # update_agents_assets,
68
+ # trigger=CronTrigger(hour=0, minute=0, timezone="UTC"),
69
+ # id="update_agent_assets",
70
+ # name="Update agent assets",
71
+ # replace_existing=True,
72
+ # )
73
+
74
+ # Update agent action costs hourly at minute 40
75
+ scheduler.add_job(
76
+ update_agent_action_cost,
77
+ trigger=CronTrigger(minute="40", timezone="UTC"),
78
+ id="update_agent_action_cost",
79
+ name="Update agent action costs",
80
+ replace_existing=True,
81
+ )
82
+
83
+ # Update agent statistics daily at UTC 00:01
84
+ scheduler.add_job(
85
+ update_agents_statistics,
86
+ trigger=CronTrigger(hour=0, minute=1, timezone="UTC"),
87
+ id="update_agent_statistics",
88
+ name="Update agent statistics",
89
+ replace_existing=True,
90
+ )
91
+
92
+ # Run quick account consistency checks every 2 hours at the top of the hour
93
+ # Run quick account consistency checks every 2 hours at the top of the hour
94
+ from intentkit.core.account_checking import run_quick_checks, run_slow_checks
95
+
96
+ async def run_quick_account_checks():
97
+ """Run quick account consistency checks and send results to Slack."""
98
+ # logger is not defined in this scope, so we use a local logger or print
99
+ # But better to use the one from the module if we move the logger definition up or import it
100
+ import logging
101
+
102
+ logger = logging.getLogger(__name__)
103
+ logger.info("Running scheduled quick account consistency checks")
104
+ try:
105
+ _ = await run_quick_checks()
106
+ logger.info("Completed quick account consistency checks")
107
+ except Exception as e:
108
+ logger.error(f"Error running quick account consistency checks: {e}")
109
+
110
+ async def run_slow_account_checks():
111
+ """Run slow account consistency checks and send results to Slack."""
112
+ import logging
113
+
114
+ logger = logging.getLogger(__name__)
115
+ logger.info("Running scheduled slow account consistency checks")
116
+ try:
117
+ _ = await run_slow_checks()
118
+ logger.info("Completed slow account consistency checks")
119
+ except Exception as e:
120
+ logger.error(f"Error running slow account consistency checks: {e}")
121
+
122
+ scheduler.add_job(
123
+ run_quick_account_checks,
124
+ trigger=CronTrigger(
125
+ hour="*/2", minute="30", timezone="UTC"
126
+ ), # Run every 2 hours
127
+ id="quick_account_checks",
128
+ name="Quick Account Consistency Checks",
129
+ replace_existing=True,
130
+ )
131
+
132
+ # Run slow account consistency checks once a day at midnight UTC
133
+ scheduler.add_job(
134
+ run_slow_account_checks,
135
+ trigger=CronTrigger(
136
+ hour="0,12", minute="0", timezone="UTC"
137
+ ), # Run 2 times a day
138
+ id="slow_account_checks",
139
+ name="Slow Account Consistency Checks",
140
+ replace_existing=True,
141
+ )
142
+
143
+ return scheduler