intentkit 0.6.13.dev2__py3-none-any.whl → 0.8.17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of intentkit might be problematic. Click here for more details.

Files changed (385) hide show
  1. intentkit/__init__.py +1 -1
  2. intentkit/abstracts/agent.py +4 -5
  3. intentkit/abstracts/engine.py +5 -5
  4. intentkit/abstracts/graph.py +14 -7
  5. intentkit/abstracts/skill.py +6 -144
  6. intentkit/abstracts/twitter.py +4 -5
  7. intentkit/clients/__init__.py +5 -2
  8. intentkit/clients/cdp.py +101 -141
  9. intentkit/clients/twitter.py +83 -62
  10. intentkit/clients/web3.py +29 -0
  11. intentkit/config/config.py +8 -5
  12. intentkit/core/agent.py +472 -195
  13. intentkit/core/asset.py +253 -0
  14. intentkit/core/chat.py +51 -0
  15. intentkit/core/client.py +1 -1
  16. intentkit/core/credit.py +460 -130
  17. intentkit/core/engine.py +262 -233
  18. intentkit/core/node.py +15 -16
  19. intentkit/core/prompt.py +62 -28
  20. intentkit/core/scheduler.py +92 -0
  21. intentkit/core/statistics.py +168 -0
  22. intentkit/models/agent.py +1096 -949
  23. intentkit/models/agent_data.py +68 -38
  24. intentkit/models/agent_public.json +98 -0
  25. intentkit/models/agent_schema.json +54 -439
  26. intentkit/models/app_setting.py +96 -33
  27. intentkit/models/chat.py +74 -27
  28. intentkit/models/conversation.py +8 -8
  29. intentkit/models/credit.py +362 -74
  30. intentkit/models/db.py +26 -8
  31. intentkit/models/db_mig.py +2 -2
  32. intentkit/models/llm.csv +28 -0
  33. intentkit/models/llm.py +185 -350
  34. intentkit/models/redis.py +6 -4
  35. intentkit/models/skill.py +186 -72
  36. intentkit/models/skills.csv +174 -0
  37. intentkit/models/user.py +82 -24
  38. intentkit/skills/acolyt/__init__.py +2 -9
  39. intentkit/skills/acolyt/ask.py +3 -4
  40. intentkit/skills/acolyt/base.py +4 -9
  41. intentkit/skills/acolyt/schema.json +4 -3
  42. intentkit/skills/aixbt/__init__.py +2 -13
  43. intentkit/skills/aixbt/base.py +1 -7
  44. intentkit/skills/aixbt/projects.py +14 -15
  45. intentkit/skills/aixbt/schema.json +4 -4
  46. intentkit/skills/allora/__init__.py +2 -9
  47. intentkit/skills/allora/base.py +4 -9
  48. intentkit/skills/allora/price.py +3 -4
  49. intentkit/skills/allora/schema.json +3 -2
  50. intentkit/skills/base.py +248 -85
  51. intentkit/skills/basename/__init__.py +51 -0
  52. intentkit/skills/basename/base.py +11 -0
  53. intentkit/skills/basename/basename.svg +11 -0
  54. intentkit/skills/basename/schema.json +58 -0
  55. intentkit/skills/carv/__init__.py +115 -121
  56. intentkit/skills/carv/base.py +184 -185
  57. intentkit/skills/carv/fetch_news.py +3 -3
  58. intentkit/skills/carv/onchain_query.py +4 -4
  59. intentkit/skills/carv/schema.json +134 -137
  60. intentkit/skills/carv/token_info_and_price.py +5 -5
  61. intentkit/skills/casino/README.md +254 -0
  62. intentkit/skills/casino/__init__.py +86 -0
  63. intentkit/skills/casino/base.py +17 -0
  64. intentkit/skills/casino/casino.png +0 -0
  65. intentkit/skills/casino/deck_draw.py +127 -0
  66. intentkit/skills/casino/deck_shuffle.py +118 -0
  67. intentkit/skills/casino/dice_roll.py +100 -0
  68. intentkit/skills/casino/schema.json +77 -0
  69. intentkit/skills/casino/utils.py +107 -0
  70. intentkit/skills/cdp/__init__.py +22 -84
  71. intentkit/skills/cdp/base.py +1 -7
  72. intentkit/skills/cdp/schema.json +11 -314
  73. intentkit/skills/chainlist/__init__.py +2 -7
  74. intentkit/skills/chainlist/base.py +1 -7
  75. intentkit/skills/chainlist/chain_lookup.py +18 -18
  76. intentkit/skills/chainlist/schema.json +3 -5
  77. intentkit/skills/common/__init__.py +2 -9
  78. intentkit/skills/common/base.py +1 -7
  79. intentkit/skills/common/current_time.py +1 -2
  80. intentkit/skills/common/schema.json +2 -2
  81. intentkit/skills/cookiefun/__init__.py +6 -9
  82. intentkit/skills/cookiefun/base.py +2 -7
  83. intentkit/skills/cookiefun/get_account_details.py +7 -7
  84. intentkit/skills/cookiefun/get_account_feed.py +19 -19
  85. intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
  86. intentkit/skills/cookiefun/get_sectors.py +3 -3
  87. intentkit/skills/cookiefun/schema.json +1 -3
  88. intentkit/skills/cookiefun/search_accounts.py +9 -9
  89. intentkit/skills/cryptocompare/__init__.py +7 -24
  90. intentkit/skills/cryptocompare/api.py +2 -3
  91. intentkit/skills/cryptocompare/base.py +11 -25
  92. intentkit/skills/cryptocompare/fetch_news.py +4 -5
  93. intentkit/skills/cryptocompare/fetch_price.py +6 -7
  94. intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
  95. intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
  96. intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
  97. intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
  98. intentkit/skills/cryptocompare/schema.json +3 -3
  99. intentkit/skills/cryptopanic/__init__.py +7 -10
  100. intentkit/skills/cryptopanic/base.py +51 -55
  101. intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
  102. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
  103. intentkit/skills/cryptopanic/schema.json +105 -103
  104. intentkit/skills/dapplooker/__init__.py +2 -9
  105. intentkit/skills/dapplooker/base.py +4 -9
  106. intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
  107. intentkit/skills/dapplooker/schema.json +3 -5
  108. intentkit/skills/defillama/__init__.py +24 -74
  109. intentkit/skills/defillama/api.py +6 -9
  110. intentkit/skills/defillama/base.py +11 -21
  111. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
  112. intentkit/skills/defillama/coins/fetch_block.py +6 -8
  113. intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
  114. intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
  115. intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
  116. intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
  117. intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
  118. intentkit/skills/defillama/config/chains.py +1 -3
  119. intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
  120. intentkit/skills/defillama/schema.json +5 -1
  121. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
  122. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
  123. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
  124. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
  125. intentkit/skills/defillama/tests/api_integration.test.py +1 -1
  126. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
  127. intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
  128. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
  129. intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
  130. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
  131. intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
  132. intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
  133. intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
  134. intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
  135. intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
  136. intentkit/skills/defillama/yields/fetch_pools.py +26 -30
  137. intentkit/skills/dexscreener/README.md +154 -0
  138. intentkit/skills/dexscreener/__init__.py +97 -93
  139. intentkit/skills/dexscreener/base.py +125 -133
  140. intentkit/skills/dexscreener/get_pair_info.py +158 -0
  141. intentkit/skills/dexscreener/get_token_pairs.py +165 -0
  142. intentkit/skills/dexscreener/get_tokens_info.py +212 -0
  143. intentkit/skills/dexscreener/model/search_token_response.py +80 -82
  144. intentkit/skills/dexscreener/schema.json +91 -48
  145. intentkit/skills/dexscreener/search_token.py +182 -321
  146. intentkit/skills/dexscreener/utils.py +420 -0
  147. intentkit/skills/dune_analytics/__init__.py +7 -9
  148. intentkit/skills/dune_analytics/base.py +48 -52
  149. intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
  150. intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
  151. intentkit/skills/dune_analytics/schema.json +104 -99
  152. intentkit/skills/elfa/__init__.py +5 -18
  153. intentkit/skills/elfa/base.py +10 -14
  154. intentkit/skills/elfa/mention.py +19 -21
  155. intentkit/skills/elfa/schema.json +3 -2
  156. intentkit/skills/elfa/stats.py +4 -4
  157. intentkit/skills/elfa/tokens.py +12 -12
  158. intentkit/skills/elfa/utils.py +26 -28
  159. intentkit/skills/enso/__init__.py +11 -31
  160. intentkit/skills/enso/base.py +50 -35
  161. intentkit/skills/enso/best_yield.py +16 -24
  162. intentkit/skills/enso/networks.py +6 -11
  163. intentkit/skills/enso/prices.py +11 -13
  164. intentkit/skills/enso/route.py +34 -38
  165. intentkit/skills/enso/schema.json +3 -2
  166. intentkit/skills/enso/tokens.py +29 -38
  167. intentkit/skills/enso/wallet.py +76 -191
  168. intentkit/skills/erc20/__init__.py +50 -0
  169. intentkit/skills/erc20/base.py +11 -0
  170. intentkit/skills/erc20/erc20.svg +5 -0
  171. intentkit/skills/erc20/schema.json +74 -0
  172. intentkit/skills/erc721/__init__.py +53 -0
  173. intentkit/skills/erc721/base.py +11 -0
  174. intentkit/skills/erc721/erc721.svg +5 -0
  175. intentkit/skills/erc721/schema.json +90 -0
  176. intentkit/skills/firecrawl/README.md +11 -5
  177. intentkit/skills/firecrawl/__init__.py +5 -18
  178. intentkit/skills/firecrawl/base.py +4 -11
  179. intentkit/skills/firecrawl/clear.py +4 -8
  180. intentkit/skills/firecrawl/crawl.py +19 -19
  181. intentkit/skills/firecrawl/query.py +4 -3
  182. intentkit/skills/firecrawl/schema.json +6 -8
  183. intentkit/skills/firecrawl/scrape.py +150 -40
  184. intentkit/skills/firecrawl/utils.py +50 -42
  185. intentkit/skills/github/__init__.py +2 -7
  186. intentkit/skills/github/base.py +1 -7
  187. intentkit/skills/github/github_search.py +1 -2
  188. intentkit/skills/github/schema.json +3 -4
  189. intentkit/skills/heurist/__init__.py +8 -27
  190. intentkit/skills/heurist/base.py +4 -9
  191. intentkit/skills/heurist/image_generation_animagine_xl.py +12 -13
  192. intentkit/skills/heurist/image_generation_arthemy_comics.py +12 -13
  193. intentkit/skills/heurist/image_generation_arthemy_real.py +12 -13
  194. intentkit/skills/heurist/image_generation_braindance.py +12 -13
  195. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +12 -13
  196. intentkit/skills/heurist/image_generation_flux_1_dev.py +12 -13
  197. intentkit/skills/heurist/image_generation_sdxl.py +12 -13
  198. intentkit/skills/heurist/schema.json +2 -2
  199. intentkit/skills/http/__init__.py +4 -15
  200. intentkit/skills/http/base.py +1 -7
  201. intentkit/skills/http/get.py +21 -16
  202. intentkit/skills/http/post.py +23 -18
  203. intentkit/skills/http/put.py +23 -18
  204. intentkit/skills/http/schema.json +4 -5
  205. intentkit/skills/lifi/__init__.py +8 -13
  206. intentkit/skills/lifi/base.py +1 -7
  207. intentkit/skills/lifi/schema.json +17 -8
  208. intentkit/skills/lifi/token_execute.py +36 -30
  209. intentkit/skills/lifi/token_quote.py +8 -10
  210. intentkit/skills/lifi/utils.py +104 -51
  211. intentkit/skills/moralis/__init__.py +6 -10
  212. intentkit/skills/moralis/api.py +6 -7
  213. intentkit/skills/moralis/base.py +5 -10
  214. intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
  215. intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
  216. intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
  217. intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
  218. intentkit/skills/moralis/schema.json +7 -2
  219. intentkit/skills/morpho/__init__.py +52 -0
  220. intentkit/skills/morpho/base.py +11 -0
  221. intentkit/skills/morpho/morpho.svg +12 -0
  222. intentkit/skills/morpho/schema.json +73 -0
  223. intentkit/skills/nation/__init__.py +4 -9
  224. intentkit/skills/nation/base.py +5 -10
  225. intentkit/skills/nation/nft_check.py +3 -4
  226. intentkit/skills/nation/schema.json +4 -3
  227. intentkit/skills/onchain.py +23 -0
  228. intentkit/skills/openai/__init__.py +17 -18
  229. intentkit/skills/openai/base.py +10 -14
  230. intentkit/skills/openai/dalle_image_generation.py +3 -8
  231. intentkit/skills/openai/gpt_avatar_generator.py +102 -0
  232. intentkit/skills/openai/gpt_image_generation.py +4 -8
  233. intentkit/skills/openai/gpt_image_mini_generator.py +91 -0
  234. intentkit/skills/openai/gpt_image_to_image.py +4 -8
  235. intentkit/skills/openai/image_to_text.py +3 -7
  236. intentkit/skills/openai/schema.json +34 -3
  237. intentkit/skills/portfolio/__init__.py +11 -35
  238. intentkit/skills/portfolio/base.py +33 -19
  239. intentkit/skills/portfolio/schema.json +3 -5
  240. intentkit/skills/portfolio/token_balances.py +21 -21
  241. intentkit/skills/portfolio/wallet_approvals.py +17 -18
  242. intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
  243. intentkit/skills/portfolio/wallet_history.py +31 -31
  244. intentkit/skills/portfolio/wallet_net_worth.py +13 -13
  245. intentkit/skills/portfolio/wallet_nfts.py +19 -19
  246. intentkit/skills/portfolio/wallet_profitability.py +18 -18
  247. intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
  248. intentkit/skills/portfolio/wallet_stats.py +3 -3
  249. intentkit/skills/portfolio/wallet_swaps.py +19 -19
  250. intentkit/skills/pyth/__init__.py +50 -0
  251. intentkit/skills/pyth/base.py +11 -0
  252. intentkit/skills/pyth/pyth.svg +6 -0
  253. intentkit/skills/pyth/schema.json +75 -0
  254. intentkit/skills/skills.toml +40 -0
  255. intentkit/skills/slack/__init__.py +5 -17
  256. intentkit/skills/slack/base.py +3 -9
  257. intentkit/skills/slack/get_channel.py +8 -8
  258. intentkit/skills/slack/get_message.py +9 -9
  259. intentkit/skills/slack/schedule_message.py +5 -5
  260. intentkit/skills/slack/schema.json +2 -2
  261. intentkit/skills/slack/send_message.py +3 -5
  262. intentkit/skills/supabase/__init__.py +7 -23
  263. intentkit/skills/supabase/base.py +9 -13
  264. intentkit/skills/supabase/delete_data.py +5 -6
  265. intentkit/skills/supabase/fetch_data.py +13 -14
  266. intentkit/skills/supabase/insert_data.py +5 -6
  267. intentkit/skills/supabase/invoke_function.py +7 -8
  268. intentkit/skills/supabase/schema.json +2 -3
  269. intentkit/skills/supabase/update_data.py +7 -8
  270. intentkit/skills/supabase/upsert_data.py +5 -6
  271. intentkit/skills/superfluid/__init__.py +53 -0
  272. intentkit/skills/superfluid/base.py +11 -0
  273. intentkit/skills/superfluid/schema.json +89 -0
  274. intentkit/skills/superfluid/superfluid.svg +6 -0
  275. intentkit/skills/system/__init__.py +7 -24
  276. intentkit/skills/system/add_autonomous_task.py +10 -12
  277. intentkit/skills/system/delete_autonomous_task.py +2 -2
  278. intentkit/skills/system/edit_autonomous_task.py +14 -18
  279. intentkit/skills/system/list_autonomous_tasks.py +3 -5
  280. intentkit/skills/system/read_agent_api_key.py +6 -4
  281. intentkit/skills/system/regenerate_agent_api_key.py +6 -4
  282. intentkit/skills/system/schema.json +6 -8
  283. intentkit/skills/tavily/__init__.py +3 -12
  284. intentkit/skills/tavily/base.py +4 -9
  285. intentkit/skills/tavily/schema.json +3 -5
  286. intentkit/skills/tavily/tavily_extract.py +2 -4
  287. intentkit/skills/tavily/tavily_search.py +4 -6
  288. intentkit/skills/token/__init__.py +5 -10
  289. intentkit/skills/token/base.py +7 -11
  290. intentkit/skills/token/erc20_transfers.py +19 -19
  291. intentkit/skills/token/schema.json +3 -6
  292. intentkit/skills/token/token_analytics.py +3 -3
  293. intentkit/skills/token/token_price.py +13 -13
  294. intentkit/skills/token/token_search.py +9 -9
  295. intentkit/skills/twitter/__init__.py +11 -35
  296. intentkit/skills/twitter/base.py +23 -35
  297. intentkit/skills/twitter/follow_user.py +3 -7
  298. intentkit/skills/twitter/get_mentions.py +6 -13
  299. intentkit/skills/twitter/get_timeline.py +5 -13
  300. intentkit/skills/twitter/get_user_by_username.py +3 -7
  301. intentkit/skills/twitter/get_user_tweets.py +6 -14
  302. intentkit/skills/twitter/like_tweet.py +3 -7
  303. intentkit/skills/twitter/post_tweet.py +23 -12
  304. intentkit/skills/twitter/reply_tweet.py +21 -12
  305. intentkit/skills/twitter/retweet.py +3 -7
  306. intentkit/skills/twitter/schema.json +1 -0
  307. intentkit/skills/twitter/search_tweets.py +5 -13
  308. intentkit/skills/unrealspeech/__init__.py +2 -7
  309. intentkit/skills/unrealspeech/base.py +2 -8
  310. intentkit/skills/unrealspeech/schema.json +2 -5
  311. intentkit/skills/unrealspeech/text_to_speech.py +8 -8
  312. intentkit/skills/venice_audio/__init__.py +98 -106
  313. intentkit/skills/venice_audio/base.py +117 -121
  314. intentkit/skills/venice_audio/input.py +41 -41
  315. intentkit/skills/venice_audio/schema.json +151 -152
  316. intentkit/skills/venice_audio/venice_audio.py +38 -21
  317. intentkit/skills/venice_image/__init__.py +147 -154
  318. intentkit/skills/venice_image/api.py +138 -138
  319. intentkit/skills/venice_image/base.py +185 -192
  320. intentkit/skills/venice_image/config.py +33 -35
  321. intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
  322. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
  323. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
  324. intentkit/skills/venice_image/image_generation/image_generation_base.py +9 -9
  325. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
  326. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
  327. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
  328. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
  329. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
  330. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
  331. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
  332. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
  333. intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
  334. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
  335. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
  336. intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
  337. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
  338. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
  339. intentkit/skills/venice_image/schema.json +267 -267
  340. intentkit/skills/venice_image/utils.py +77 -78
  341. intentkit/skills/web_scraper/__init__.py +5 -18
  342. intentkit/skills/web_scraper/base.py +21 -7
  343. intentkit/skills/web_scraper/document_indexer.py +7 -6
  344. intentkit/skills/web_scraper/schema.json +2 -6
  345. intentkit/skills/web_scraper/scrape_and_index.py +15 -15
  346. intentkit/skills/web_scraper/utils.py +62 -63
  347. intentkit/skills/web_scraper/website_indexer.py +17 -19
  348. intentkit/skills/weth/__init__.py +49 -0
  349. intentkit/skills/weth/base.py +11 -0
  350. intentkit/skills/weth/schema.json +58 -0
  351. intentkit/skills/weth/weth.svg +6 -0
  352. intentkit/skills/wow/__init__.py +51 -0
  353. intentkit/skills/wow/base.py +11 -0
  354. intentkit/skills/wow/schema.json +89 -0
  355. intentkit/skills/wow/wow.svg +7 -0
  356. intentkit/skills/x402/__init__.py +61 -0
  357. intentkit/skills/x402/ask_agent.py +98 -0
  358. intentkit/skills/x402/base.py +99 -0
  359. intentkit/skills/x402/http_request.py +117 -0
  360. intentkit/skills/x402/schema.json +45 -0
  361. intentkit/skills/x402/x402.webp +0 -0
  362. intentkit/skills/xmtp/__init__.py +4 -15
  363. intentkit/skills/xmtp/base.py +61 -2
  364. intentkit/skills/xmtp/price.py +18 -13
  365. intentkit/skills/xmtp/schema.json +69 -71
  366. intentkit/skills/xmtp/swap.py +22 -25
  367. intentkit/skills/xmtp/transfer.py +71 -32
  368. intentkit/utils/chain.py +3 -3
  369. intentkit/utils/error.py +14 -1
  370. intentkit/utils/logging.py +2 -4
  371. intentkit/utils/s3.py +59 -7
  372. intentkit/utils/schema.py +100 -0
  373. intentkit/utils/slack_alert.py +7 -8
  374. {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/METADATA +14 -16
  375. intentkit-0.8.17.dist-info/RECORD +466 -0
  376. intentkit/abstracts/exception.py +0 -9
  377. intentkit/core/skill.py +0 -200
  378. intentkit/models/generator.py +0 -347
  379. intentkit/skills/cdp/get_balance.py +0 -110
  380. intentkit/skills/cdp/swap.py +0 -121
  381. intentkit/skills/moralis/tests/__init__.py +0 -0
  382. intentkit/skills/moralis/tests/test_wallet.py +0 -511
  383. intentkit-0.6.13.dev2.dist-info/RECORD +0 -409
  384. {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/WHEEL +0 -0
  385. {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/licenses/LICENSE +0 -0
intentkit/core/engine.py CHANGED
@@ -17,11 +17,10 @@ import textwrap
17
17
  import time
18
18
  import traceback
19
19
  from datetime import datetime
20
- from typing import Optional
21
20
 
22
21
  import sqlalchemy
23
22
  from epyxid import XID
24
- from fastapi import HTTPException
23
+ from langchain_core.language_models import BaseChatModel
25
24
  from langchain_core.messages import (
26
25
  BaseMessage,
27
26
  HumanMessage,
@@ -30,21 +29,22 @@ from langchain_core.tools import BaseTool
30
29
  from langgraph.errors import GraphRecursionError
31
30
  from langgraph.graph.state import CompiledStateGraph
32
31
  from langgraph.prebuilt import create_react_agent
32
+ from langgraph.runtime import Runtime
33
33
  from sqlalchemy import func, update
34
34
  from sqlalchemy.exc import SQLAlchemyError
35
35
 
36
36
  from intentkit.abstracts.graph import AgentContext, AgentError, AgentState
37
37
  from intentkit.config.config import config
38
+ from intentkit.core.chat import clear_thread_memory
38
39
  from intentkit.core.credit import expense_message, expense_skill
39
40
  from intentkit.core.node import PreModelNode, post_model_node
40
41
  from intentkit.core.prompt import (
41
42
  create_formatted_prompt_function,
42
43
  explain_prompt,
43
44
  )
44
- from intentkit.core.skill import skill_store
45
45
  from intentkit.models.agent import Agent, AgentTable
46
46
  from intentkit.models.agent_data import AgentData, AgentQuota
47
- from intentkit.models.app_setting import AppSetting
47
+ from intentkit.models.app_setting import AppSetting, SystemMessageType
48
48
  from intentkit.models.chat import (
49
49
  AuthorType,
50
50
  ChatMessage,
@@ -53,27 +53,24 @@ from intentkit.models.chat import (
53
53
  )
54
54
  from intentkit.models.credit import CreditAccount, OwnerType
55
55
  from intentkit.models.db import get_langgraph_checkpointer, get_session
56
- from intentkit.models.llm import LLMModelInfo, LLMProvider
57
- from intentkit.models.skill import AgentSkillData, ThreadSkillData
56
+ from intentkit.models.llm import LLMModelInfo, LLMProvider, create_llm_model
57
+ from intentkit.models.skill import AgentSkillData, ChatSkillData, Skill
58
58
  from intentkit.models.user import User
59
59
  from intentkit.utils.error import IntentKitAPIError
60
60
 
61
61
  logger = logging.getLogger(__name__)
62
62
 
63
-
64
63
  # Global variable to cache all agent executors
65
64
  _agents: dict[str, CompiledStateGraph] = {}
66
- _private_agents: dict[str, CompiledStateGraph] = {}
67
65
 
68
66
  # Global dictionaries to cache agent update times
69
67
  _agents_updated: dict[str, datetime] = {}
70
- _private_agents_updated: dict[str, datetime] = {}
71
68
 
72
69
 
73
- async def create_agent(
74
- agent: Agent, is_private: bool = False, has_search: bool = False
70
+ async def build_agent(
71
+ agent: Agent, agent_data: AgentData, custom_skills: list[BaseTool] = []
75
72
  ) -> CompiledStateGraph:
76
- """Create an AI agent with specified configuration and tools.
73
+ """Build an AI agent with specified configuration and tools.
77
74
 
78
75
  This function:
79
76
  1. Initializes LLM with specified model
@@ -83,16 +80,13 @@ async def create_agent(
83
80
 
84
81
  Args:
85
82
  agent (Agent): Agent configuration object
86
- is_private (bool, optional): Flag indicating whether the agent is private. Defaults to False.
87
- has_search (bool, optional): Flag indicating whether to include search tools. Defaults to False.
83
+ agent_data (AgentData): Agent data object
84
+ custom_skills (list[BaseTool], optional): Designed for advanced user who directly
85
+ call this function to inject custom skills into the agent tool node.
88
86
 
89
87
  Returns:
90
88
  CompiledStateGraph: Initialized LangChain agent
91
89
  """
92
- agent_data = await AgentData.get(agent.id)
93
-
94
- # ==== Initialize LLM using the LLM abstraction.
95
- from intentkit.models.llm import create_llm_model
96
90
 
97
91
  # Create the LLM model instance
98
92
  llm_model = await create_llm_model(
@@ -102,17 +96,12 @@ async def create_agent(
102
96
  presence_penalty=agent.presence_penalty,
103
97
  )
104
98
 
105
- # Get the LLM instance
106
- llm = await llm_model.create_instance(config)
107
-
108
- # Get the token limit from the model info
109
- input_token_limit = min(config.input_token_limit, llm_model.info.context_length)
110
-
111
99
  # ==== Store buffered conversation history in memory.
112
100
  memory = get_langgraph_checkpointer()
113
101
 
114
102
  # ==== Load skills
115
103
  tools: list[BaseTool | dict] = []
104
+ private_tools: list[BaseTool | dict] = []
116
105
 
117
106
  if agent.skills:
118
107
  for k, v in agent.skills.items():
@@ -121,50 +110,75 @@ async def create_agent(
121
110
  try:
122
111
  skill_module = importlib.import_module(f"intentkit.skills.{k}")
123
112
  if hasattr(skill_module, "get_skills"):
113
+ # all
124
114
  skill_tools = await skill_module.get_skills(
125
- v, is_private, skill_store, agent_id=agent.id
115
+ v, False, agent_id=agent.id, agent=agent
126
116
  )
127
117
  if skill_tools and len(skill_tools) > 0:
128
118
  tools.extend(skill_tools)
119
+ # private
120
+ skill_private_tools = await skill_module.get_skills(
121
+ v, True, agent_id=agent.id, agent=agent
122
+ )
123
+ if skill_private_tools and len(skill_private_tools) > 0:
124
+ private_tools.extend(skill_private_tools)
129
125
  else:
130
126
  logger.error(f"Skill {k} does not have get_skills function")
131
127
  except ImportError as e:
132
128
  logger.error(f"Could not import skill module: {k} ({e})")
133
129
 
130
+ # add custom skills to private tools
131
+ if custom_skills and len(custom_skills) > 0:
132
+ private_tools.extend(custom_skills)
133
+
134
134
  # filter the duplicate tools
135
135
  tools = list({tool.name: tool for tool in tools}.values())
136
-
137
- # Add search tools if requested
138
- if (
139
- has_search
140
- and llm_model.info.provider == LLMProvider.OPENAI
141
- and llm_model.info.supports_search
142
- and not agent.model.startswith(
143
- "gpt-5"
144
- ) # tmp disable gpt-5 search since package bugs
145
- ):
146
- tools.append({"type": "web_search_preview"})
136
+ private_tools = list({tool.name: tool for tool in private_tools}.values())
147
137
 
148
138
  # Create the formatted_prompt function using the refactored prompt module
149
139
  formatted_prompt = create_formatted_prompt_function(agent, agent_data)
150
140
 
151
- for tool in tools:
141
+ # bind tools to llm
142
+ async def select_model(
143
+ state: AgentState, runtime: Runtime[AgentContext]
144
+ ) -> BaseChatModel:
145
+ llm_params = {}
146
+ context = runtime.context
147
+ if context.search:
148
+ if llm_model.info.supports_search:
149
+ if llm_model.info.provider == LLMProvider.OPENAI:
150
+ tools.append({"type": "web_search"})
151
+ private_tools.append({"type": "web_search"})
152
+ if agent.model.startswith("gpt-5-"):
153
+ llm_params["reasoning_effort"] = "low"
154
+ if llm_model.info.provider == LLMProvider.XAI:
155
+ llm_params["search_parameters"] = {"mode": "auto"}
156
+ # TODO: else use a search skill
157
+ # build llm now
158
+ llm = await llm_model.create_instance(llm_params)
159
+ if context.is_private:
160
+ return llm.bind_tools(private_tools)
161
+ return llm.bind_tools(tools)
162
+
163
+ for tool in private_tools:
152
164
  logger.info(
153
- f"[{agent.id}{'-private' if is_private else ''}] loaded tool: {tool.name if isinstance(tool, BaseTool) else tool}"
165
+ f"[{agent.id}] loaded tool: {tool.name if isinstance(tool, BaseTool) else tool}"
154
166
  )
155
167
 
156
168
  # Pre model hook
169
+ summarize_llm = await create_llm_model(model_name="gpt-5-mini")
170
+ summarize_model = await summarize_llm.create_instance()
157
171
  pre_model_hook = PreModelNode(
158
- model=llm,
172
+ model=summarize_model,
159
173
  short_term_memory_strategy=agent.short_term_memory_strategy,
160
- max_tokens=input_token_limit // 2,
161
- max_summary_tokens=2048, # later we can let agent to set this
174
+ max_tokens=llm_model.info.context_length // 2,
175
+ max_summary_tokens=2048,
162
176
  )
163
177
 
164
178
  # Create ReAct Agent using the LLM and CDP Agentkit tools.
165
179
  executor = create_react_agent(
166
- model=llm,
167
- tools=tools,
180
+ model=select_model,
181
+ tools=private_tools,
168
182
  prompt=formatted_prompt,
169
183
  pre_model_hook=pre_model_hook,
170
184
  post_model_hook=post_model_node if config.payment_enabled else None,
@@ -178,7 +192,23 @@ async def create_agent(
178
192
  return executor
179
193
 
180
194
 
181
- async def initialize_agent(aid, is_private=False):
195
+ async def create_agent(agent: Agent) -> CompiledStateGraph:
196
+ """Create an AI agent with specified configuration and tools.
197
+
198
+ This function maintains backward compatibility by calling build_agent internally.
199
+
200
+ Args:
201
+ agent (Agent): Agent configuration object
202
+ is_private (bool, optional): Flag indicating whether the agent is private. Defaults to False.
203
+
204
+ Returns:
205
+ CompiledStateGraph: Initialized LangChain agent
206
+ """
207
+ agent_data = await AgentData.get(agent.id)
208
+ return await build_agent(agent, agent_data)
209
+
210
+
211
+ async def initialize_agent(aid):
182
212
  """Initialize an AI agent with specified configuration and tools.
183
213
 
184
214
  This function:
@@ -197,63 +227,41 @@ async def initialize_agent(aid, is_private=False):
197
227
  HTTPException: If agent not found (404) or database error (500)
198
228
  """
199
229
  # get the agent from the database
200
- agent: Optional[Agent] = await Agent.get(aid)
230
+ agent: Agent | None = await Agent.get(aid)
201
231
  if not agent:
202
- raise HTTPException(status_code=404, detail="Agent not found")
203
-
204
- # Determine if search should be enabled based on model capabilities
205
- from intentkit.models.llm import create_llm_model
206
-
207
- llm_model = await create_llm_model(
208
- model_name=agent.model,
209
- temperature=agent.temperature,
210
- frequency_penalty=agent.frequency_penalty,
211
- presence_penalty=agent.presence_penalty,
212
- )
213
- has_search = (
214
- llm_model.info.provider == LLMProvider.OPENAI and llm_model.info.supports_search
215
- )
232
+ raise IntentKitAPIError(
233
+ status_code=404, key="AgentNotFound", message="Agent not found"
234
+ )
216
235
 
217
236
  # Create the agent using the new create_agent function
218
- executor = await create_agent(agent, is_private, has_search)
237
+ executor = await create_agent(agent)
219
238
 
220
239
  # Cache the agent executor
221
- if is_private:
222
- _private_agents[aid] = executor
223
- _private_agents_updated[aid] = agent.updated_at
224
- else:
225
- _agents[aid] = executor
226
- _agents_updated[aid] = agent.updated_at
240
+ _agents[aid] = executor
241
+ _agents_updated[aid] = agent.deployed_at if agent.deployed_at else agent.updated_at
227
242
 
228
243
 
229
- async def agent_executor(
230
- agent_id: str, is_private: bool
231
- ) -> (CompiledStateGraph, float):
244
+ async def agent_executor(agent_id: str) -> tuple[CompiledStateGraph, float]:
232
245
  start = time.perf_counter()
233
246
  agent = await Agent.get(agent_id)
234
247
  if not agent:
235
- raise HTTPException(status_code=404, detail="Agent not found")
236
- agents = _private_agents if is_private else _agents
237
- agents_updated = _private_agents_updated if is_private else _agents_updated
238
-
248
+ raise IntentKitAPIError(
249
+ status_code=404, key="AgentNotFound", message="Agent not found"
250
+ )
251
+ updated_at = agent.deployed_at if agent.deployed_at else agent.updated_at
239
252
  # Check if agent needs reinitialization due to updates
240
253
  needs_reinit = False
241
- if agent_id in agents:
242
- if (
243
- agent_id not in agents_updated
244
- or agent.updated_at != agents_updated[agent_id]
245
- ):
254
+ if agent_id in _agents:
255
+ if agent_id not in _agents_updated or updated_at != _agents_updated[agent_id]:
246
256
  needs_reinit = True
247
- logger.info(
248
- f"Reinitializing agent {agent_id} due to updates, private mode: {is_private}"
249
- )
257
+ logger.info(f"Reinitializing agent {agent_id} due to updates")
250
258
 
251
259
  # cold start or needs reinitialization
252
260
  cold_start_cost = 0.0
253
- if (agent_id not in agents) or needs_reinit:
254
- await initialize_agent(agent_id, is_private)
261
+ if (agent_id not in _agents) or needs_reinit:
262
+ await initialize_agent(agent_id)
255
263
  cold_start_cost = time.perf_counter() - start
256
- return agents[agent_id], cold_start_cost
264
+ return _agents[agent_id], cold_start_cost
257
265
 
258
266
 
259
267
  async def stream_agent(message: ChatMessageCreate):
@@ -272,24 +280,62 @@ async def stream_agent(message: ChatMessageCreate):
272
280
  Yields:
273
281
  ChatMessage: Individual response messages including timing information
274
282
  """
283
+ agent = await Agent.get(message.agent_id)
284
+ executor, cold_start_cost = await agent_executor(message.agent_id)
285
+ message.cold_start_cost = cold_start_cost
286
+ async for chat_message in stream_agent_raw(message, agent, executor):
287
+ yield chat_message
288
+
289
+
290
+ async def stream_agent_raw(
291
+ message: ChatMessageCreate, agent: Agent, executor: CompiledStateGraph
292
+ ):
275
293
  start = time.perf_counter()
276
294
  # make sure reply_to is set
277
295
  message.reply_to = message.id
278
296
 
279
297
  # save input message first
280
- input = await message.save()
298
+ user_message = await message.save()
299
+
300
+ # temporary debug logging for telegram messages
301
+ if user_message.author_type == AuthorType.TELEGRAM:
302
+ logger.info(
303
+ f"[TELEGRAM DEBUG] Agent: {user_message.agent_id} | Chat: {user_message.chat_id} | Message: {user_message.message}"
304
+ )
281
305
 
282
- # agent
283
- agent = await Agent.get(input.agent_id)
306
+ if re.search(
307
+ r"(@clear|/clear)(?!\w)",
308
+ user_message.message.strip(),
309
+ re.IGNORECASE,
310
+ ):
311
+ await clear_thread_memory(user_message.agent_id, user_message.chat_id)
312
+
313
+ confirmation_message = ChatMessageCreate(
314
+ id=str(XID()),
315
+ agent_id=user_message.agent_id,
316
+ chat_id=user_message.chat_id,
317
+ user_id=user_message.user_id,
318
+ author_id=user_message.agent_id,
319
+ author_type=AuthorType.AGENT,
320
+ model=agent.model,
321
+ thread_type=user_message.author_type,
322
+ reply_to=user_message.id,
323
+ message="Memory in context has been cleared.",
324
+ time_cost=time.perf_counter() - start,
325
+ )
326
+
327
+ yield await confirmation_message.save()
328
+ return
284
329
 
285
- # model
286
330
  model = await LLMModelInfo.get(agent.model)
287
331
 
288
332
  payment_enabled = config.payment_enabled
333
+ if user_message.author_type == AuthorType.X402:
334
+ payment_enabled = False
289
335
 
290
336
  # check user balance
291
337
  if payment_enabled:
292
- if not input.user_id or not agent.owner:
338
+ if not user_message.user_id or not agent.owner:
293
339
  raise IntentKitAPIError(
294
340
  500,
295
341
  "PaymentError",
@@ -298,24 +344,22 @@ async def stream_agent(message: ChatMessageCreate):
298
344
  if agent.fee_percentage and agent.fee_percentage > 100:
299
345
  owner = await User.get(agent.owner)
300
346
  if owner and agent.fee_percentage > 100 + owner.nft_count * 10:
301
- error_message_create = ChatMessageCreate(
302
- id=str(XID()),
303
- agent_id=input.agent_id,
304
- chat_id=input.chat_id,
305
- user_id=input.user_id,
306
- author_id=input.agent_id,
307
- author_type=AuthorType.SYSTEM,
308
- thread_type=input.author_type,
309
- reply_to=input.id,
310
- message="If you are the owner of this agent, please Update the Service Fee % to be in compliance with the Nation guidelines (Max 100% + 10% per Nation Pass NFT held)",
347
+ error_message_create = await ChatMessageCreate.from_system_message(
348
+ SystemMessageType.SERVICE_FEE_ERROR,
349
+ agent_id=user_message.agent_id,
350
+ chat_id=user_message.chat_id,
351
+ user_id=user_message.user_id,
352
+ author_id=user_message.agent_id,
353
+ thread_type=user_message.author_type,
354
+ reply_to=user_message.id,
311
355
  time_cost=time.perf_counter() - start,
312
356
  )
313
357
  error_message = await error_message_create.save()
314
358
  yield error_message
315
359
  return
316
360
  # payer
317
- payer = input.user_id
318
- if input.author_type in [
361
+ payer = user_message.user_id
362
+ if user_message.author_type in [
319
363
  AuthorType.TELEGRAM,
320
364
  AuthorType.TWITTER,
321
365
  AuthorType.API,
@@ -336,16 +380,14 @@ async def stream_agent(message: ChatMessageCreate):
336
380
  abuse_check = False
337
381
  if abuse_check and payer != agent.owner and user_account.free_credits > 0:
338
382
  if quota and quota.free_income_daily > 24000:
339
- error_message_create = ChatMessageCreate(
340
- id=str(XID()),
341
- agent_id=input.agent_id,
342
- chat_id=input.chat_id,
343
- user_id=input.user_id,
344
- author_id=input.agent_id,
345
- author_type=AuthorType.SYSTEM,
346
- thread_type=input.author_type,
347
- reply_to=input.id,
348
- message="This Agent has reached its free CAP income limit for today! Start using paid CAPs or wait until this limit expires in less than 24 hours.",
383
+ error_message_create = await ChatMessageCreate.from_system_message(
384
+ SystemMessageType.DAILY_USAGE_LIMIT_EXCEEDED,
385
+ agent_id=user_message.agent_id,
386
+ chat_id=user_message.chat_id,
387
+ user_id=user_message.user_id,
388
+ author_id=user_message.agent_id,
389
+ thread_type=user_message.author_type,
390
+ reply_to=user_message.id,
349
391
  time_cost=time.perf_counter() - start,
350
392
  )
351
393
  error_message = await error_message_create.save()
@@ -356,16 +398,14 @@ async def stream_agent(message: ChatMessageCreate):
356
398
  if quota and quota.avg_action_cost > 0:
357
399
  avg_count = quota.avg_action_cost
358
400
  if not user_account.has_sufficient_credits(avg_count):
359
- error_message_create = ChatMessageCreate(
360
- id=str(XID()),
361
- agent_id=input.agent_id,
362
- chat_id=input.chat_id,
363
- user_id=input.user_id,
364
- author_id=input.agent_id,
365
- author_type=AuthorType.SYSTEM,
366
- thread_type=input.author_type,
367
- reply_to=input.id,
368
- message="Insufficient balance.",
401
+ error_message_create = await ChatMessageCreate.from_system_message(
402
+ SystemMessageType.INSUFFICIENT_BALANCE,
403
+ agent_id=user_message.agent_id,
404
+ chat_id=user_message.chat_id,
405
+ user_id=user_message.user_id,
406
+ author_id=user_message.agent_id,
407
+ thread_type=user_message.author_type,
408
+ reply_to=user_message.id,
369
409
  time_cost=time.perf_counter() - start,
370
410
  )
371
411
  error_message = await error_message_create.save()
@@ -373,26 +413,22 @@ async def stream_agent(message: ChatMessageCreate):
373
413
  return
374
414
 
375
415
  is_private = False
376
- if input.user_id == agent.owner:
416
+ if user_message.user_id == agent.owner:
377
417
  is_private = True
378
418
 
379
- executor, cold_start_cost = await agent_executor(input.agent_id, is_private)
380
- last = start + cold_start_cost
419
+ last = start
381
420
 
382
421
  # Extract images from attachments
383
422
  image_urls = []
384
- if input.attachments:
423
+ if user_message.attachments:
385
424
  image_urls = [
386
425
  att["url"]
387
- for att in input.attachments
426
+ for att in user_message.attachments
388
427
  if "type" in att and att["type"] == "image" and "url" in att
389
428
  ]
390
429
 
391
430
  # Process input message to handle @skill patterns
392
- if config.admin_llm_skill_control:
393
- input_message = await explain_prompt(input.message)
394
- else:
395
- input_message = input.message
431
+ input_message = await explain_prompt(user_message.message)
396
432
 
397
433
  # super mode
398
434
  recursion_limit = 30
@@ -402,9 +438,11 @@ async def stream_agent(message: ChatMessageCreate):
402
438
  input_message = re.sub(r"\b@super\b", "", input_message).strip()
403
439
 
404
440
  # llm native search
441
+ search = False
405
442
  if re.search(r"\b@search\b", input_message) or re.search(
406
443
  r"\b@web\b", input_message
407
444
  ):
445
+ search = True
408
446
  if model.supports_search:
409
447
  input_message = re.sub(
410
448
  r"\b@search\b",
@@ -421,8 +459,8 @@ async def stream_agent(message: ChatMessageCreate):
421
459
  input_message = re.sub(r"\b@web\b", "", input_message).strip()
422
460
 
423
461
  # content to llm
424
- content = [
425
- {"type": "text", "text": input_message},
462
+ messages = [
463
+ HumanMessage(content=input_message),
426
464
  ]
427
465
  # if the model doesn't natively support image parsing, add the image URLs to the message
428
466
  if image_urls:
@@ -430,25 +468,24 @@ async def stream_agent(message: ChatMessageCreate):
430
468
  agent.has_image_parser_skill(is_private=is_private)
431
469
  and not model.supports_image_input
432
470
  ):
433
- input_message += f"\n\nImages:\n{'\n'.join(image_urls)}"
434
- content = [
435
- {"type": "text", "text": input_message},
471
+ image_urls_text = "\n".join(image_urls)
472
+ input_message += f"\n\nImages:\n{image_urls_text}"
473
+ messages = [
474
+ HumanMessage(content=input_message),
436
475
  ]
437
476
  else:
438
477
  # anyway, pass it directly to LLM
439
- content.extend(
478
+ messages.extend(
440
479
  [
441
- {"type": "image_url", "image_url": {"url": image_url}}
480
+ HumanMessage(
481
+ content={"type": "image_url", "image_url": {"url": image_url}}
482
+ )
442
483
  for image_url in image_urls
443
484
  ]
444
485
  )
445
486
 
446
- messages = [
447
- HumanMessage(content=content),
448
- ]
449
-
450
487
  # stream config
451
- thread_id = f"{input.agent_id}-{input.chat_id}"
488
+ thread_id = f"{user_message.agent_id}-{user_message.chat_id}"
452
489
  stream_config = {
453
490
  "configurable": {
454
491
  "thread_id": thread_id,
@@ -456,13 +493,18 @@ async def stream_agent(message: ChatMessageCreate):
456
493
  "recursion_limit": recursion_limit,
457
494
  }
458
495
 
496
+ def get_agent() -> Agent:
497
+ return agent
498
+
459
499
  context = AgentContext(
460
- agent_id=input.agent_id,
461
- chat_id=input.chat_id,
462
- user_id=input.user_id,
463
- app_id=input.app_id,
464
- entrypoint=input.author_type,
500
+ agent_id=user_message.agent_id,
501
+ get_agent=get_agent,
502
+ chat_id=user_message.chat_id,
503
+ user_id=user_message.user_id,
504
+ app_id=user_message.app_id,
505
+ entrypoint=user_message.author_type,
465
506
  is_private=is_private,
507
+ search=search,
466
508
  payer=payer if payment_enabled else None,
467
509
  )
468
510
 
@@ -498,14 +540,14 @@ async def stream_agent(message: ChatMessageCreate):
498
540
  # agent message
499
541
  chat_message_create = ChatMessageCreate(
500
542
  id=str(XID()),
501
- agent_id=input.agent_id,
502
- chat_id=input.chat_id,
503
- user_id=input.user_id,
504
- author_id=input.agent_id,
543
+ agent_id=user_message.agent_id,
544
+ chat_id=user_message.chat_id,
545
+ user_id=user_message.user_id,
546
+ author_id=user_message.agent_id,
505
547
  author_type=AuthorType.AGENT,
506
548
  model=agent.model,
507
- thread_type=input.author_type,
508
- reply_to=input.id,
549
+ thread_type=user_message.author_type,
550
+ reply_to=user_message.id,
509
551
  message=content,
510
552
  input_tokens=(
511
553
  msg.usage_metadata.get("input_tokens", 0)
@@ -520,9 +562,6 @@ async def stream_agent(message: ChatMessageCreate):
520
562
  time_cost=this_time - last,
521
563
  )
522
564
  last = this_time
523
- if cold_start_cost > 0:
524
- chat_message_create.cold_start_cost = cold_start_cost
525
- cold_start_cost = 0
526
565
  # handle message and payment in one transaction
527
566
  async with get_session() as session:
528
567
  # payment
@@ -543,7 +582,7 @@ async def stream_agent(message: ChatMessageCreate):
543
582
  for tool_output in tool_outputs:
544
583
  if tool_output.get("type") == "web_search_call":
545
584
  logger.info(
546
- f"[{input.agent_id}] Found web_search_call in additional_kwargs"
585
+ f"[{user_message.agent_id}] Found web_search_call in additional_kwargs"
547
586
  )
548
587
  amount += 35
549
588
  break
@@ -551,11 +590,13 @@ async def stream_agent(message: ChatMessageCreate):
551
590
  session,
552
591
  payer,
553
592
  chat_message_create.id,
554
- input.id,
593
+ user_message.id,
555
594
  amount,
556
595
  agent,
557
596
  )
558
- logger.info(f"[{input.agent_id}] expense message: {amount}")
597
+ logger.info(
598
+ f"[{user_message.agent_id}] expense message: {amount}"
599
+ )
559
600
  chat_message_create.credit_event_id = credit_event.id
560
601
  chat_message_create.credit_cost = credit_event.total_amount
561
602
  chat_message = await chat_message_create.save_in_session(
@@ -606,14 +647,14 @@ async def stream_agent(message: ChatMessageCreate):
606
647
  break
607
648
  skill_message_create = ChatMessageCreate(
608
649
  id=str(XID()),
609
- agent_id=input.agent_id,
610
- chat_id=input.chat_id,
611
- user_id=input.user_id,
612
- author_id=input.agent_id,
650
+ agent_id=user_message.agent_id,
651
+ chat_id=user_message.chat_id,
652
+ user_id=user_message.user_id,
653
+ author_id=user_message.agent_id,
613
654
  author_type=AuthorType.SKILL,
614
655
  model=agent.model,
615
- thread_type=input.author_type,
616
- reply_to=input.id,
656
+ thread_type=user_message.author_type,
657
+ reply_to=user_message.id,
617
658
  message="",
618
659
  skill_calls=skill_calls,
619
660
  attachments=cached_attachments,
@@ -634,9 +675,6 @@ async def stream_agent(message: ChatMessageCreate):
634
675
  time_cost=this_time - last,
635
676
  )
636
677
  last = this_time
637
- if cold_start_cost > 0:
638
- skill_message_create.cold_start_cost = cold_start_cost
639
- cold_start_cost = 0
640
678
  # save message and credit in one transaction
641
679
  async with get_session() as session:
642
680
  if payment_enabled:
@@ -650,7 +688,7 @@ async def stream_agent(message: ChatMessageCreate):
650
688
  session,
651
689
  payer,
652
690
  skill_message_create.id,
653
- input.id,
691
+ user_message.id,
654
692
  message_amount,
655
693
  agent,
656
694
  )
@@ -664,11 +702,14 @@ async def stream_agent(message: ChatMessageCreate):
664
702
  for skill_call in skill_calls:
665
703
  if not skill_call["success"]:
666
704
  continue
705
+ skill = await Skill.get(skill_call["name"])
706
+ if not skill:
707
+ continue
667
708
  payment_event = await expense_skill(
668
709
  session,
669
710
  payer,
670
711
  skill_message_create.id,
671
- input.id,
712
+ user_message.id,
672
713
  skill_call["id"],
673
714
  skill_call["name"],
674
715
  agent,
@@ -676,7 +717,7 @@ async def stream_agent(message: ChatMessageCreate):
676
717
  skill_call["credit_event_id"] = payment_event.id
677
718
  skill_call["credit_cost"] = payment_event.total_amount
678
719
  logger.info(
679
- f"[{input.agent_id}] skill payment: {skill_call}"
720
+ f"[{user_message.agent_id}] skill payment: {skill_call}"
680
721
  )
681
722
  skill_message_create.skill_calls = skill_calls
682
723
  skill_message = await skill_message_create.save_in_session(session)
@@ -702,38 +743,33 @@ async def stream_agent(message: ChatMessageCreate):
702
743
  content = msg.content[0]
703
744
  post_model_message_create = ChatMessageCreate(
704
745
  id=str(XID()),
705
- agent_id=input.agent_id,
706
- chat_id=input.chat_id,
707
- user_id=input.user_id,
708
- author_id=input.agent_id,
746
+ agent_id=user_message.agent_id,
747
+ chat_id=user_message.chat_id,
748
+ user_id=user_message.user_id,
749
+ author_id=user_message.agent_id,
709
750
  author_type=AuthorType.AGENT,
710
751
  model=agent.model,
711
- thread_type=input.author_type,
712
- reply_to=input.id,
752
+ thread_type=user_message.author_type,
753
+ reply_to=user_message.id,
713
754
  message=content,
714
755
  input_tokens=0,
715
756
  output_tokens=0,
716
757
  time_cost=this_time - last,
717
758
  )
718
759
  last = this_time
719
- if cold_start_cost > 0:
720
- post_model_message_create.cold_start_cost = (
721
- cold_start_cost
722
- )
723
- cold_start_cost = 0
724
760
  post_model_message = await post_model_message_create.save()
725
761
  yield post_model_message
726
- error_message_create = ChatMessageCreate(
727
- id=str(XID()),
728
- agent_id=input.agent_id,
729
- chat_id=input.chat_id,
730
- user_id=input.user_id,
731
- author_id=input.agent_id,
732
- author_type=AuthorType.SYSTEM,
733
- thread_type=input.author_type,
734
- reply_to=input.id,
735
- message="Insufficient balance.",
736
- time_cost=0,
762
+ error_message_create = (
763
+ await ChatMessageCreate.from_system_message(
764
+ SystemMessageType.INSUFFICIENT_BALANCE,
765
+ agent_id=user_message.agent_id,
766
+ chat_id=user_message.chat_id,
767
+ user_id=user_message.user_id,
768
+ author_id=user_message.agent_id,
769
+ thread_type=user_message.author_type,
770
+ reply_to=user_message.id,
771
+ time_cost=0,
772
+ )
737
773
  )
738
774
  error_message = await error_message_create.save()
739
775
  yield error_message
@@ -749,16 +785,14 @@ async def stream_agent(message: ChatMessageCreate):
749
785
  f"failed to execute agent: {str(e)}\n{error_traceback}",
750
786
  extra={"thread_id": thread_id},
751
787
  )
752
- error_message_create = ChatMessageCreate(
753
- id=str(XID()),
754
- agent_id=input.agent_id,
755
- chat_id=input.chat_id,
756
- user_id=input.user_id,
757
- author_id=input.agent_id,
758
- author_type=AuthorType.SYSTEM,
759
- thread_type=input.author_type,
760
- reply_to=input.id,
761
- message="Agent Internal Error",
788
+ error_message_create = await ChatMessageCreate.from_system_message(
789
+ SystemMessageType.AGENT_INTERNAL_ERROR,
790
+ agent_id=user_message.agent_id,
791
+ chat_id=user_message.chat_id,
792
+ user_id=user_message.user_id,
793
+ author_id=user_message.agent_id,
794
+ thread_type=user_message.author_type,
795
+ reply_to=user_message.id,
762
796
  time_cost=time.perf_counter() - start,
763
797
  )
764
798
  error_message = await error_message_create.save()
@@ -768,18 +802,16 @@ async def stream_agent(message: ChatMessageCreate):
768
802
  error_traceback = traceback.format_exc()
769
803
  logger.error(
770
804
  f"reached recursion limit: {str(e)}\n{error_traceback}",
771
- extra={"thread_id": thread_id, "agent_id": input.agent_id},
805
+ extra={"thread_id": thread_id, "agent_id": user_message.agent_id},
772
806
  )
773
- error_message_create = ChatMessageCreate(
774
- id=str(XID()),
775
- agent_id=input.agent_id,
776
- chat_id=input.chat_id,
777
- user_id=input.user_id,
778
- author_id=input.agent_id,
779
- author_type=AuthorType.SYSTEM,
780
- thread_type=input.author_type,
781
- reply_to=input.id,
782
- message="Step Limit Error",
807
+ error_message_create = await ChatMessageCreate.from_system_message(
808
+ SystemMessageType.STEP_LIMIT_EXCEEDED,
809
+ agent_id=user_message.agent_id,
810
+ chat_id=user_message.chat_id,
811
+ user_id=user_message.user_id,
812
+ author_id=user_message.agent_id,
813
+ thread_type=user_message.author_type,
814
+ reply_to=user_message.id,
783
815
  time_cost=time.perf_counter() - start,
784
816
  )
785
817
  error_message = await error_message_create.save()
@@ -789,22 +821,21 @@ async def stream_agent(message: ChatMessageCreate):
789
821
  error_traceback = traceback.format_exc()
790
822
  logger.error(
791
823
  f"failed to execute agent: {str(e)}\n{error_traceback}",
792
- extra={"thread_id": thread_id, "agent_id": input.agent_id},
824
+ extra={"thread_id": thread_id, "agent_id": user_message.agent_id},
793
825
  )
794
- error_message_create = ChatMessageCreate(
795
- id=str(XID()),
796
- agent_id=input.agent_id,
797
- chat_id=input.chat_id,
798
- user_id=input.user_id,
799
- author_id=input.agent_id,
800
- author_type=AuthorType.SYSTEM,
801
- thread_type=input.author_type,
802
- reply_to=input.id,
803
- message="Agent Internal Error",
826
+ error_message_create = await ChatMessageCreate.from_system_message(
827
+ SystemMessageType.AGENT_INTERNAL_ERROR,
828
+ agent_id=user_message.agent_id,
829
+ chat_id=user_message.chat_id,
830
+ user_id=user_message.user_id,
831
+ author_id=user_message.agent_id,
832
+ thread_type=user_message.author_type,
833
+ reply_to=user_message.id,
804
834
  time_cost=time.perf_counter() - start,
805
835
  )
806
836
  error_message = await error_message_create.save()
807
837
  yield error_message
838
+ await clear_thread_memory(user_message.agent_id, user_message.chat_id)
808
839
  return
809
840
 
810
841
 
@@ -859,14 +890,15 @@ async def clean_agent_memory(
859
890
  # get the agent from the database
860
891
  try:
861
892
  if not clean_skill and not clean_agent:
862
- raise HTTPException(
893
+ raise IntentKitAPIError(
863
894
  status_code=400,
864
- detail="at least one of skills data or agent memory should be true.",
895
+ key="InvalidCleanupParameters",
896
+ message="at least one of skills data or agent memory should be true",
865
897
  )
866
898
 
867
899
  if clean_skill:
868
900
  await AgentSkillData.clean_data(agent_id)
869
- await ThreadSkillData.clean_data(agent_id, chat_id)
901
+ await ChatSkillData.clean_data(agent_id, chat_id)
870
902
 
871
903
  async with get_session() as db:
872
904
  if clean_agent:
@@ -908,7 +940,7 @@ async def clean_agent_memory(
908
940
  except SQLAlchemyError as e:
909
941
  # Handle other SQLAlchemy-related errors
910
942
  logger.error(e)
911
- raise HTTPException(status_code=500, detail=str(e))
943
+ raise IntentKitAPIError(status_code=500, key="DatabaseError", message=str(e))
912
944
  except Exception as e:
913
945
  logger.error("failed to cleanup the agent memory: " + str(e))
914
946
  raise e
@@ -917,10 +949,7 @@ async def clean_agent_memory(
917
949
  async def thread_stats(agent_id: str, chat_id: str) -> list[BaseMessage]:
918
950
  thread_id = f"{agent_id}-{chat_id}"
919
951
  stream_config = {"configurable": {"thread_id": thread_id}}
920
- is_private = False
921
- if chat_id.startswith("owner") or chat_id.startswith("autonomous"):
922
- is_private = True
923
- executor, _ = await agent_executor(agent_id, is_private)
952
+ executor, _ = await agent_executor(agent_id)
924
953
  snap = await executor.aget_state(stream_config)
925
954
  if snap.values and "messages" in snap.values:
926
955
  return snap.values["messages"]