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/credit.py CHANGED
@@ -1,10 +1,8 @@
1
1
  import logging
2
2
  from datetime import datetime
3
3
  from decimal import ROUND_HALF_UP, Decimal
4
- from typing import List, Optional, Tuple
5
4
 
6
5
  from epyxid import XID
7
- from fastapi import HTTPException
8
6
  from pydantic import BaseModel
9
7
  from sqlalchemy import desc, select
10
8
  from sqlalchemy.ext.asyncio import AsyncSession
@@ -22,6 +20,7 @@ from intentkit.models.credit import (
22
20
  DEFAULT_PLATFORM_ACCOUNT_REFILL,
23
21
  DEFAULT_PLATFORM_ACCOUNT_REWARD,
24
22
  DEFAULT_PLATFORM_ACCOUNT_SKILL,
23
+ DEFAULT_PLATFORM_ACCOUNT_WITHDRAW,
25
24
  CreditAccount,
26
25
  CreditAccountTable,
27
26
  CreditDebit,
@@ -38,6 +37,7 @@ from intentkit.models.credit import (
38
37
  )
39
38
  from intentkit.models.db import get_session
40
39
  from intentkit.models.skill import Skill
40
+ from intentkit.utils.error import IntentKitAPIError
41
41
  from intentkit.utils.slack_alert import send_slack_message
42
42
 
43
43
  logger = logging.getLogger(__name__)
@@ -49,7 +49,7 @@ FOURPLACES = Decimal("0.0001")
49
49
  async def update_credit_event_note(
50
50
  session: AsyncSession,
51
51
  event_id: str,
52
- note: Optional[str] = None,
52
+ note: str | None = None,
53
53
  ) -> CreditEvent:
54
54
  """
55
55
  Update the note of a credit event.
@@ -71,7 +71,9 @@ async def update_credit_event_note(
71
71
  event = result.scalar_one_or_none()
72
72
 
73
73
  if not event:
74
- raise HTTPException(status_code=404, detail="Credit event not found")
74
+ raise IntentKitAPIError(
75
+ status_code=404, key="CreditEventNotFound", message="Credit event not found"
76
+ )
75
77
 
76
78
  # Update the note
77
79
  event.note = note
@@ -86,7 +88,7 @@ async def recharge(
86
88
  user_id: str,
87
89
  amount: Decimal,
88
90
  upstream_tx_id: str,
89
- note: Optional[str] = None,
91
+ note: str | None = None,
90
92
  ) -> CreditAccount:
91
93
  """
92
94
  Recharge credits to a user account.
@@ -117,8 +119,9 @@ async def recharge(
117
119
  session=session,
118
120
  owner_type=OwnerType.USER,
119
121
  owner_id=user_id,
120
- amount=amount,
121
- credit_type=CreditType.PERMANENT, # Recharge adds to permanent credits
122
+ amount_details={
123
+ CreditType.PERMANENT: amount
124
+ }, # Recharge adds to permanent credits
122
125
  event_id=event_id,
123
126
  )
124
127
 
@@ -149,6 +152,9 @@ async def recharge(
149
152
  + user_account.reward_credits,
150
153
  base_amount=amount,
151
154
  base_original_amount=amount,
155
+ base_free_amount=Decimal("0"), # No free credits involved in base amount
156
+ base_reward_amount=Decimal("0"), # No reward credits involved in base amount
157
+ base_permanent_amount=amount, # All base amount is permanent for recharge
152
158
  permanent_amount=amount, # Set permanent_amount since this is a permanent credit
153
159
  free_amount=Decimal("0"), # No free credits involved
154
160
  reward_amount=Decimal("0"), # No reward credits involved
@@ -168,6 +174,9 @@ async def recharge(
168
174
  credit_debit=CreditDebit.CREDIT,
169
175
  change_amount=amount,
170
176
  credit_type=CreditType.PERMANENT,
177
+ free_amount=Decimal("0"),
178
+ reward_amount=Decimal("0"),
179
+ permanent_amount=amount,
171
180
  )
172
181
  session.add(user_tx)
173
182
 
@@ -180,6 +189,9 @@ async def recharge(
180
189
  credit_debit=CreditDebit.DEBIT,
181
190
  change_amount=amount,
182
191
  credit_type=CreditType.PERMANENT,
192
+ free_amount=Decimal("0"),
193
+ reward_amount=Decimal("0"),
194
+ permanent_amount=amount,
183
195
  )
184
196
  session.add(platform_tx)
185
197
 
@@ -202,13 +214,178 @@ async def recharge(
202
214
  return user_account
203
215
 
204
216
 
217
+ async def withdraw(
218
+ session: AsyncSession,
219
+ agent_id: str,
220
+ amount: Decimal,
221
+ upstream_tx_id: str,
222
+ note: str | None = None,
223
+ ) -> CreditAccount:
224
+ """
225
+ Withdraw credits from an agent account to platform account.
226
+
227
+ Args:
228
+ session: Async session to use for database operations
229
+ agent_id: ID of the agent to withdraw from
230
+ amount: Amount of credits to withdraw
231
+ upstream_tx_id: ID of the upstream transaction
232
+ note: Optional note for the transaction
233
+
234
+ Returns:
235
+ Updated agent credit account
236
+ """
237
+ # Check for idempotency - prevent duplicate transactions
238
+ await CreditEvent.check_upstream_tx_id_exists(
239
+ session, UpstreamType.API, upstream_tx_id
240
+ )
241
+
242
+ if amount <= Decimal("0"):
243
+ raise ValueError("Withdraw amount must be positive")
244
+
245
+ # Get agent to retrieve user_id from agent.owner
246
+ agent = await Agent.get(agent_id)
247
+ if not agent:
248
+ raise IntentKitAPIError(
249
+ status_code=404, key="AgentNotFound", message="Agent not found"
250
+ )
251
+
252
+ if not agent.owner:
253
+ raise IntentKitAPIError(
254
+ status_code=400, key="AgentNoOwner", message="Agent has no owner"
255
+ )
256
+
257
+ # Get agent wallet address
258
+ agent_data = await AgentData.get(agent.id)
259
+ agent_wallet_address = agent_data.evm_wallet_address if agent_data else None
260
+
261
+ user_id = agent.owner
262
+
263
+ # Get agent account to check balance
264
+ agent_account = await CreditAccount.get_in_session(
265
+ session=session,
266
+ owner_type=OwnerType.AGENT,
267
+ owner_id=agent_id,
268
+ )
269
+
270
+ # Check if agent has sufficient permanent credits
271
+ if agent_account.credits < amount:
272
+ raise IntentKitAPIError(
273
+ status_code=400,
274
+ key="InsufficientBalance",
275
+ message=f"Insufficient balance. Available: {agent_account.credits}, Required: {amount}",
276
+ )
277
+
278
+ # 1. Create credit event record first to get event_id
279
+ event_id = str(XID())
280
+
281
+ # 2. Update agent account - deduct credits
282
+ updated_agent_account = await CreditAccount.deduction_in_session(
283
+ session=session,
284
+ owner_type=OwnerType.AGENT,
285
+ owner_id=agent_id,
286
+ credit_type=CreditType.PERMANENT,
287
+ amount=amount,
288
+ event_id=event_id,
289
+ )
290
+
291
+ # 3. Update platform withdraw account - add credits
292
+ platform_account = await CreditAccount.income_in_session(
293
+ session=session,
294
+ owner_type=OwnerType.PLATFORM,
295
+ owner_id=DEFAULT_PLATFORM_ACCOUNT_WITHDRAW,
296
+ amount_details={
297
+ CreditType.PERMANENT: amount
298
+ }, # Withdraw adds to platform permanent credits
299
+ event_id=event_id,
300
+ )
301
+
302
+ # 4. Create credit event record
303
+ event = CreditEventTable(
304
+ id=event_id,
305
+ event_type=EventType.WITHDRAW,
306
+ user_id=user_id,
307
+ upstream_type=UpstreamType.API,
308
+ upstream_tx_id=upstream_tx_id,
309
+ direction=Direction.EXPENSE,
310
+ account_id=updated_agent_account.id,
311
+ total_amount=amount,
312
+ credit_type=CreditType.PERMANENT,
313
+ credit_types=[CreditType.PERMANENT],
314
+ balance_after=updated_agent_account.credits
315
+ + updated_agent_account.free_credits
316
+ + updated_agent_account.reward_credits,
317
+ base_amount=amount,
318
+ base_original_amount=amount,
319
+ base_free_amount=Decimal("0"), # No free credits involved in base amount
320
+ base_reward_amount=Decimal("0"), # No reward credits involved in base amount
321
+ base_permanent_amount=amount, # All base amount is permanent for withdraw
322
+ permanent_amount=amount, # Set permanent_amount since this is a permanent credit
323
+ free_amount=Decimal("0"), # No free credits involved
324
+ reward_amount=Decimal("0"), # No reward credits involved
325
+ agent_wallet_address=agent_wallet_address, # Include agent wallet address
326
+ note=note,
327
+ )
328
+ session.add(event)
329
+ await session.flush()
330
+
331
+ # 5. Create credit transaction records
332
+ # 5.1 Agent account transaction (debit)
333
+ agent_tx = CreditTransactionTable(
334
+ id=str(XID()),
335
+ account_id=updated_agent_account.id,
336
+ event_id=event_id,
337
+ tx_type=TransactionType.WITHDRAW,
338
+ credit_debit=CreditDebit.DEBIT,
339
+ change_amount=amount,
340
+ credit_type=CreditType.PERMANENT,
341
+ free_amount=Decimal("0"),
342
+ reward_amount=Decimal("0"),
343
+ permanent_amount=amount,
344
+ )
345
+ session.add(agent_tx)
346
+
347
+ # 5.2 Platform withdraw account transaction (credit)
348
+ platform_tx = CreditTransactionTable(
349
+ id=str(XID()),
350
+ account_id=platform_account.id,
351
+ event_id=event_id,
352
+ tx_type=TransactionType.WITHDRAW,
353
+ credit_debit=CreditDebit.CREDIT,
354
+ change_amount=amount,
355
+ credit_type=CreditType.PERMANENT,
356
+ free_amount=Decimal("0"),
357
+ reward_amount=Decimal("0"),
358
+ permanent_amount=amount,
359
+ )
360
+ session.add(platform_tx)
361
+
362
+ # Commit all changes
363
+ await session.commit()
364
+
365
+ # Send Slack notification for withdraw
366
+ try:
367
+ send_slack_message(
368
+ f"💸 **Credit Withdraw**\n"
369
+ f"• Agent ID: `{agent_id}`\n"
370
+ f"• User ID: `{user_id}`\n"
371
+ f"• Amount: `{amount}` credits\n"
372
+ f"• Transaction ID: `{upstream_tx_id}`\n"
373
+ f"• New Balance: `{updated_agent_account.credits}` credits\n"
374
+ f"• Note: {note or 'N/A'}"
375
+ )
376
+ except Exception as e:
377
+ logger.error(f"Failed to send Slack notification for withdraw: {str(e)}")
378
+
379
+ return updated_agent_account
380
+
381
+
205
382
  async def reward(
206
383
  session: AsyncSession,
207
384
  user_id: str,
208
385
  amount: Decimal,
209
386
  upstream_tx_id: str,
210
- note: Optional[str] = None,
211
- reward_type: Optional[RewardType] = RewardType.REWARD,
387
+ note: str | None = None,
388
+ reward_type: RewardType | None = RewardType.REWARD,
212
389
  ) -> CreditAccount:
213
390
  """
214
391
  Reward a user account with reward credits.
@@ -239,8 +416,7 @@ async def reward(
239
416
  session=session,
240
417
  owner_type=OwnerType.USER,
241
418
  owner_id=user_id,
242
- amount=amount,
243
- credit_type=CreditType.REWARD, # Reward adds to reward credits
419
+ amount_details={CreditType.REWARD: amount}, # Reward adds to reward credits
244
420
  event_id=event_id,
245
421
  )
246
422
 
@@ -271,6 +447,11 @@ async def reward(
271
447
  + user_account.reward_credits,
272
448
  base_amount=amount,
273
449
  base_original_amount=amount,
450
+ base_free_amount=Decimal("0"), # No free credits involved in base amount
451
+ base_reward_amount=amount, # All base amount is reward for reward events
452
+ base_permanent_amount=Decimal(
453
+ "0"
454
+ ), # No permanent credits involved in base amount
274
455
  reward_amount=amount, # Set reward_amount since this is a reward credit
275
456
  free_amount=Decimal("0"), # No free credits involved
276
457
  permanent_amount=Decimal("0"), # No permanent credits involved
@@ -290,6 +471,9 @@ async def reward(
290
471
  credit_debit=CreditDebit.CREDIT,
291
472
  change_amount=amount,
292
473
  credit_type=CreditType.REWARD,
474
+ free_amount=Decimal("0"),
475
+ reward_amount=amount,
476
+ permanent_amount=Decimal("0"),
293
477
  )
294
478
  session.add(user_tx)
295
479
 
@@ -302,6 +486,9 @@ async def reward(
302
486
  credit_debit=CreditDebit.DEBIT,
303
487
  change_amount=amount,
304
488
  credit_type=CreditType.REWARD,
489
+ free_amount=Decimal("0"),
490
+ reward_amount=amount,
491
+ permanent_amount=Decimal("0"),
305
492
  )
306
493
  session.add(platform_tx)
307
494
 
@@ -375,8 +562,7 @@ async def adjustment(
375
562
  session=session,
376
563
  owner_type=OwnerType.USER,
377
564
  owner_id=user_id,
378
- amount=abs_amount,
379
- credit_type=credit_type,
565
+ amount_details={credit_type: abs_amount},
380
566
  event_id=event_id,
381
567
  )
382
568
  else:
@@ -407,8 +593,7 @@ async def adjustment(
407
593
  session=session,
408
594
  owner_type=OwnerType.PLATFORM,
409
595
  owner_id=DEFAULT_PLATFORM_ACCOUNT_ADJUSTMENT,
410
- amount=abs_amount,
411
- credit_type=credit_type,
596
+ amount_details={credit_type: abs_amount},
412
597
  event_id=event_id,
413
598
  )
414
599
 
@@ -441,6 +626,9 @@ async def adjustment(
441
626
  + user_account.reward_credits,
442
627
  base_amount=abs_amount,
443
628
  base_original_amount=abs_amount,
629
+ base_free_amount=free_amount,
630
+ base_reward_amount=reward_amount,
631
+ base_permanent_amount=permanent_amount,
444
632
  free_amount=free_amount,
445
633
  reward_amount=reward_amount,
446
634
  permanent_amount=permanent_amount,
@@ -460,6 +648,9 @@ async def adjustment(
460
648
  credit_debit=credit_debit_user,
461
649
  change_amount=abs_amount,
462
650
  credit_type=credit_type,
651
+ free_amount=free_amount,
652
+ reward_amount=reward_amount,
653
+ permanent_amount=permanent_amount,
463
654
  )
464
655
  session.add(user_tx)
465
656
 
@@ -472,6 +663,9 @@ async def adjustment(
472
663
  credit_debit=credit_debit_platform,
473
664
  change_amount=abs_amount,
474
665
  credit_type=credit_type,
666
+ free_amount=free_amount,
667
+ reward_amount=reward_amount,
668
+ permanent_amount=permanent_amount,
475
669
  )
476
670
  session.add(platform_tx)
477
671
 
@@ -484,8 +678,8 @@ async def adjustment(
484
678
  async def update_daily_quota(
485
679
  session: AsyncSession,
486
680
  user_id: str,
487
- free_quota: Optional[Decimal] = None,
488
- refill_amount: Optional[Decimal] = None,
681
+ free_quota: Decimal | None = None,
682
+ refill_amount: Decimal | None = None,
489
683
  upstream_tx_id: str = "",
490
684
  note: str = "",
491
685
  ) -> CreditAccount:
@@ -511,11 +705,11 @@ async def update_daily_quota(
511
705
  async def list_credit_events_by_user(
512
706
  session: AsyncSession,
513
707
  user_id: str,
514
- direction: Optional[Direction] = None,
515
- cursor: Optional[str] = None,
708
+ direction: Direction | None = None,
709
+ cursor: str | None = None,
516
710
  limit: int = 20,
517
- event_type: Optional[EventType] = None,
518
- ) -> Tuple[List[CreditEvent], Optional[str], bool]:
711
+ event_type: EventType | None = None,
712
+ ) -> tuple[list[CreditEvent], str | None, bool]:
519
713
  """
520
714
  List credit events for a user account with cursor pagination.
521
715
 
@@ -576,13 +770,13 @@ async def list_credit_events_by_user(
576
770
 
577
771
  async def list_credit_events(
578
772
  session: AsyncSession,
579
- direction: Optional[Direction] = Direction.EXPENSE,
580
- cursor: Optional[str] = None,
773
+ direction: Direction | None = Direction.EXPENSE,
774
+ cursor: str | None = None,
581
775
  limit: int = 20,
582
- event_type: Optional[EventType] = None,
583
- start_at: Optional[datetime] = None,
584
- end_at: Optional[datetime] = None,
585
- ) -> Tuple[List[CreditEvent], Optional[str], bool]:
776
+ event_type: EventType | None = None,
777
+ start_at: datetime | None = None,
778
+ end_at: datetime | None = None,
779
+ ) -> tuple[list[CreditEvent], str | None, bool]:
586
780
  """
587
781
  List all credit events with cursor pagination.
588
782
 
@@ -646,9 +840,9 @@ async def list_credit_events(
646
840
  async def list_fee_events_by_agent(
647
841
  session: AsyncSession,
648
842
  agent_id: str,
649
- cursor: Optional[str] = None,
843
+ cursor: str | None = None,
650
844
  limit: int = 20,
651
- ) -> Tuple[List[CreditEvent], Optional[str], bool]:
845
+ ) -> tuple[list[CreditEvent], str | None, bool]:
652
846
  """
653
847
  List fee events for an agent with cursor pagination.
654
848
  These events represent income for the agent from users' expenses.
@@ -728,9 +922,10 @@ async def fetch_credit_event_by_upstream_tx_id(
728
922
 
729
923
  # Raise 404 if not found
730
924
  if not result:
731
- raise HTTPException(
925
+ raise IntentKitAPIError(
732
926
  status_code=404,
733
- detail=f"Credit event with upstream_tx_id '{upstream_tx_id}' not found",
927
+ key="CreditEventNotFound",
928
+ message=f"Credit event with upstream_tx_id '{upstream_tx_id}' not found",
734
929
  )
735
930
 
736
931
  # Convert to Pydantic model and return
@@ -752,7 +947,7 @@ async def fetch_credit_event_by_id(
752
947
  The credit event if found.
753
948
 
754
949
  Raises:
755
- HTTPException: If the credit event is not found.
950
+ IntentKitAPIError: If the credit event is not found.
756
951
  """
757
952
  # Build the query to find the event by ID
758
953
  stmt = select(CreditEventTable).where(CreditEventTable.id == event_id)
@@ -762,9 +957,10 @@ async def fetch_credit_event_by_id(
762
957
 
763
958
  # Raise 404 if not found
764
959
  if not result:
765
- raise HTTPException(
960
+ raise IntentKitAPIError(
766
961
  status_code=404,
767
- detail=f"Credit event with ID '{event_id}' not found",
962
+ key="CreditEventNotFound",
963
+ message=f"Credit event with ID '{event_id}' not found",
768
964
  )
769
965
 
770
966
  # Convert to Pydantic model and return
@@ -842,34 +1038,7 @@ async def expense_message(
842
1038
  session=session, id=agent.id, amount=details.get(CreditType.FREE)
843
1039
  )
844
1040
 
845
- # 3. Update fee account - add credits
846
- message_account = await CreditAccount.income_in_session(
847
- session=session,
848
- owner_type=OwnerType.PLATFORM,
849
- owner_id=DEFAULT_PLATFORM_ACCOUNT_MESSAGE,
850
- credit_type=CreditType.PERMANENT,
851
- amount=base_amount,
852
- event_id=event_id,
853
- )
854
- platform_fee_account = await CreditAccount.income_in_session(
855
- session=session,
856
- owner_type=OwnerType.PLATFORM,
857
- owner_id=DEFAULT_PLATFORM_ACCOUNT_FEE,
858
- credit_type=CreditType.PERMANENT,
859
- amount=fee_platform_amount,
860
- event_id=event_id,
861
- )
862
- if fee_agent_amount > 0:
863
- agent_account = await CreditAccount.income_in_session(
864
- session=session,
865
- owner_type=OwnerType.AGENT,
866
- owner_id=agent.id,
867
- credit_type=CreditType.REWARD,
868
- amount=fee_agent_amount,
869
- event_id=event_id,
870
- )
871
-
872
- # 4. Create credit event record
1041
+ # 3. Calculate detailed amounts for fees based on user payment details
873
1042
  # Set the appropriate credit amount field based on credit type
874
1043
  free_amount = details.get(CreditType.FREE, Decimal("0"))
875
1044
  reward_amount = details.get(CreditType.REWARD, Decimal("0"))
@@ -925,6 +1094,52 @@ async def expense_message(
925
1094
  fee_agent_amount - fee_agent_free_amount - fee_agent_reward_amount
926
1095
  ).quantize(FOURPLACES, rounding=ROUND_HALF_UP)
927
1096
 
1097
+ # Calculate base amounts by credit type using subtraction method
1098
+ # This ensures that: permanent_amount = base_permanent_amount + fee_platform_permanent_amount + fee_agent_permanent_amount
1099
+ base_free_amount = free_amount - fee_platform_free_amount - fee_agent_free_amount
1100
+ base_reward_amount = (
1101
+ reward_amount - fee_platform_reward_amount - fee_agent_reward_amount
1102
+ )
1103
+ base_permanent_amount = (
1104
+ permanent_amount - fee_platform_permanent_amount - fee_agent_permanent_amount
1105
+ )
1106
+
1107
+ # 4. Update fee account - add credits with detailed amounts
1108
+ message_account = await CreditAccount.income_in_session(
1109
+ session=session,
1110
+ owner_type=OwnerType.PLATFORM,
1111
+ owner_id=DEFAULT_PLATFORM_ACCOUNT_MESSAGE,
1112
+ amount_details={
1113
+ CreditType.FREE: base_free_amount,
1114
+ CreditType.REWARD: base_reward_amount,
1115
+ CreditType.PERMANENT: base_permanent_amount,
1116
+ },
1117
+ event_id=event_id,
1118
+ )
1119
+ platform_fee_account = await CreditAccount.income_in_session(
1120
+ session=session,
1121
+ owner_type=OwnerType.PLATFORM,
1122
+ owner_id=DEFAULT_PLATFORM_ACCOUNT_FEE,
1123
+ amount_details={
1124
+ CreditType.FREE: fee_platform_free_amount,
1125
+ CreditType.REWARD: fee_platform_reward_amount,
1126
+ CreditType.PERMANENT: fee_platform_permanent_amount,
1127
+ },
1128
+ event_id=event_id,
1129
+ )
1130
+ if fee_agent_amount > 0:
1131
+ agent_account = await CreditAccount.income_in_session(
1132
+ session=session,
1133
+ owner_type=OwnerType.AGENT,
1134
+ owner_id=agent.id,
1135
+ amount_details={
1136
+ CreditType.FREE: fee_agent_free_amount,
1137
+ CreditType.REWARD: fee_agent_reward_amount,
1138
+ CreditType.PERMANENT: fee_agent_permanent_amount,
1139
+ },
1140
+ event_id=event_id,
1141
+ )
1142
+
928
1143
  # Get agent wallet address
929
1144
  agent_data = await AgentData.get(agent.id)
930
1145
  agent_wallet_address = agent_data.evm_wallet_address if agent_data else None
@@ -949,6 +1164,9 @@ async def expense_message(
949
1164
  + user_account.reward_credits,
950
1165
  base_amount=base_amount,
951
1166
  base_original_amount=base_original_amount,
1167
+ base_free_amount=base_free_amount,
1168
+ base_reward_amount=base_reward_amount,
1169
+ base_permanent_amount=base_permanent_amount,
952
1170
  base_llm_amount=base_llm_amount,
953
1171
  fee_platform_amount=fee_platform_amount,
954
1172
  fee_platform_free_amount=fee_platform_free_amount,
@@ -977,6 +1195,9 @@ async def expense_message(
977
1195
  credit_debit=CreditDebit.DEBIT,
978
1196
  change_amount=total_amount,
979
1197
  credit_type=credit_type,
1198
+ free_amount=free_amount,
1199
+ reward_amount=reward_amount,
1200
+ permanent_amount=permanent_amount,
980
1201
  )
981
1202
  session.add(user_tx)
982
1203
 
@@ -989,6 +1210,9 @@ async def expense_message(
989
1210
  credit_debit=CreditDebit.CREDIT,
990
1211
  change_amount=base_amount,
991
1212
  credit_type=credit_type,
1213
+ free_amount=base_free_amount,
1214
+ reward_amount=base_reward_amount,
1215
+ permanent_amount=base_permanent_amount,
992
1216
  )
993
1217
  session.add(message_tx)
994
1218
 
@@ -1001,6 +1225,9 @@ async def expense_message(
1001
1225
  credit_debit=CreditDebit.CREDIT,
1002
1226
  change_amount=fee_platform_amount,
1003
1227
  credit_type=credit_type,
1228
+ free_amount=fee_platform_free_amount,
1229
+ reward_amount=fee_platform_reward_amount,
1230
+ permanent_amount=fee_platform_permanent_amount,
1004
1231
  )
1005
1232
  session.add(platform_tx)
1006
1233
 
@@ -1014,6 +1241,9 @@ async def expense_message(
1014
1241
  credit_debit=CreditDebit.CREDIT,
1015
1242
  change_amount=fee_agent_amount,
1016
1243
  credit_type=credit_type,
1244
+ free_amount=fee_agent_free_amount,
1245
+ reward_amount=fee_agent_reward_amount,
1246
+ permanent_amount=fee_agent_permanent_amount,
1017
1247
  )
1018
1248
  session.add(agent_tx)
1019
1249
 
@@ -1170,43 +1400,7 @@ async def expense_skill(
1170
1400
  session=session, id=agent.id, amount=details[CreditType.FREE]
1171
1401
  )
1172
1402
 
1173
- # 3. Update fee account - add credits
1174
- skill_account = await CreditAccount.income_in_session(
1175
- session=session,
1176
- owner_type=OwnerType.PLATFORM,
1177
- owner_id=DEFAULT_PLATFORM_ACCOUNT_SKILL,
1178
- credit_type=CreditType.PERMANENT,
1179
- amount=skill_cost_info.base_amount,
1180
- event_id=event_id,
1181
- )
1182
- platform_account = await CreditAccount.income_in_session(
1183
- session=session,
1184
- owner_type=OwnerType.PLATFORM,
1185
- owner_id=DEFAULT_PLATFORM_ACCOUNT_FEE,
1186
- credit_type=CreditType.PERMANENT,
1187
- amount=skill_cost_info.fee_platform_amount,
1188
- event_id=event_id,
1189
- )
1190
- if skill_cost_info.fee_dev_amount > 0:
1191
- dev_account = await CreditAccount.income_in_session(
1192
- session=session,
1193
- owner_type=skill_cost_info.fee_dev_user_type,
1194
- owner_id=skill_cost_info.fee_dev_user,
1195
- credit_type=CreditType.REWARD, # put dev fee in reward
1196
- amount=skill_cost_info.fee_dev_amount,
1197
- event_id=event_id,
1198
- )
1199
- if skill_cost_info.fee_agent_amount > 0:
1200
- agent_account = await CreditAccount.income_in_session(
1201
- session=session,
1202
- owner_type=OwnerType.AGENT,
1203
- owner_id=agent.id,
1204
- credit_type=CreditType.REWARD,
1205
- amount=skill_cost_info.fee_agent_amount,
1206
- event_id=event_id,
1207
- )
1208
-
1209
- # 4. Create credit event record
1403
+ # 3. Calculate detailed amounts for fees
1210
1404
  # Set the appropriate credit amount field based on credit type
1211
1405
  free_amount = details.get(CreditType.FREE, Decimal("0"))
1212
1406
  reward_amount = details.get(CreditType.REWARD, Decimal("0"))
@@ -1306,6 +1500,78 @@ async def expense_skill(
1306
1500
  skill_cost_info.fee_dev_amount - fee_dev_free_amount - fee_dev_reward_amount
1307
1501
  ).quantize(FOURPLACES, rounding=ROUND_HALF_UP)
1308
1502
 
1503
+ # Calculate base amounts by credit type using subtraction method
1504
+ base_free_amount = (
1505
+ free_amount
1506
+ - fee_platform_free_amount
1507
+ - fee_agent_free_amount
1508
+ - fee_dev_free_amount
1509
+ )
1510
+
1511
+ base_reward_amount = (
1512
+ reward_amount
1513
+ - fee_platform_reward_amount
1514
+ - fee_agent_reward_amount
1515
+ - fee_dev_reward_amount
1516
+ )
1517
+
1518
+ base_permanent_amount = (
1519
+ permanent_amount
1520
+ - fee_platform_permanent_amount
1521
+ - fee_agent_permanent_amount
1522
+ - fee_dev_permanent_amount
1523
+ )
1524
+
1525
+ # 4. Update fee account - add credits
1526
+ skill_account = await CreditAccount.income_in_session(
1527
+ session=session,
1528
+ owner_type=OwnerType.PLATFORM,
1529
+ owner_id=DEFAULT_PLATFORM_ACCOUNT_SKILL,
1530
+ amount_details={
1531
+ CreditType.FREE: base_free_amount,
1532
+ CreditType.REWARD: base_reward_amount,
1533
+ CreditType.PERMANENT: base_permanent_amount,
1534
+ },
1535
+ event_id=event_id,
1536
+ )
1537
+ platform_account = await CreditAccount.income_in_session(
1538
+ session=session,
1539
+ owner_type=OwnerType.PLATFORM,
1540
+ owner_id=DEFAULT_PLATFORM_ACCOUNT_FEE,
1541
+ amount_details={
1542
+ CreditType.FREE: fee_platform_free_amount,
1543
+ CreditType.REWARD: fee_platform_reward_amount,
1544
+ CreditType.PERMANENT: fee_platform_permanent_amount,
1545
+ },
1546
+ event_id=event_id,
1547
+ )
1548
+ if skill_cost_info.fee_dev_amount > 0:
1549
+ dev_account = await CreditAccount.income_in_session(
1550
+ session=session,
1551
+ owner_type=skill_cost_info.fee_dev_user_type,
1552
+ owner_id=skill_cost_info.fee_dev_user,
1553
+ amount_details={
1554
+ CreditType.FREE: fee_dev_free_amount,
1555
+ CreditType.REWARD: fee_dev_reward_amount,
1556
+ CreditType.PERMANENT: fee_dev_permanent_amount,
1557
+ },
1558
+ event_id=event_id,
1559
+ )
1560
+ if skill_cost_info.fee_agent_amount > 0:
1561
+ agent_account = await CreditAccount.income_in_session(
1562
+ session=session,
1563
+ owner_type=OwnerType.AGENT,
1564
+ owner_id=agent.id,
1565
+ amount_details={
1566
+ CreditType.FREE: fee_agent_free_amount,
1567
+ CreditType.REWARD: fee_agent_reward_amount,
1568
+ CreditType.PERMANENT: fee_agent_permanent_amount,
1569
+ },
1570
+ event_id=event_id,
1571
+ )
1572
+
1573
+ # 5. Create credit event record
1574
+
1309
1575
  # Get agent wallet address
1310
1576
  agent_data = await AgentData.get(agent.id)
1311
1577
  agent_wallet_address = agent_data.evm_wallet_address if agent_data else None
@@ -1332,6 +1598,9 @@ async def expense_skill(
1332
1598
  base_amount=skill_cost_info.base_amount,
1333
1599
  base_original_amount=skill_cost_info.base_original_amount,
1334
1600
  base_skill_amount=skill_cost_info.base_skill_amount,
1601
+ base_free_amount=base_free_amount,
1602
+ base_reward_amount=base_reward_amount,
1603
+ base_permanent_amount=base_permanent_amount,
1335
1604
  fee_platform_amount=skill_cost_info.fee_platform_amount,
1336
1605
  fee_platform_free_amount=fee_platform_free_amount,
1337
1606
  fee_platform_reward_amount=fee_platform_reward_amount,
@@ -1366,6 +1635,9 @@ async def expense_skill(
1366
1635
  credit_debit=CreditDebit.DEBIT,
1367
1636
  change_amount=skill_cost_info.total_amount,
1368
1637
  credit_type=credit_type,
1638
+ free_amount=free_amount,
1639
+ reward_amount=reward_amount,
1640
+ permanent_amount=permanent_amount,
1369
1641
  )
1370
1642
  session.add(user_tx)
1371
1643
 
@@ -1378,6 +1650,9 @@ async def expense_skill(
1378
1650
  credit_debit=CreditDebit.CREDIT,
1379
1651
  change_amount=skill_cost_info.base_amount,
1380
1652
  credit_type=credit_type,
1653
+ free_amount=base_free_amount,
1654
+ reward_amount=base_reward_amount,
1655
+ permanent_amount=base_permanent_amount,
1381
1656
  )
1382
1657
  session.add(skill_tx)
1383
1658
 
@@ -1390,6 +1665,9 @@ async def expense_skill(
1390
1665
  credit_debit=CreditDebit.CREDIT,
1391
1666
  change_amount=skill_cost_info.fee_platform_amount,
1392
1667
  credit_type=credit_type,
1668
+ free_amount=fee_platform_free_amount,
1669
+ reward_amount=fee_platform_reward_amount,
1670
+ permanent_amount=fee_platform_permanent_amount,
1393
1671
  )
1394
1672
  session.add(platform_tx)
1395
1673
 
@@ -1403,6 +1681,9 @@ async def expense_skill(
1403
1681
  credit_debit=CreditDebit.CREDIT,
1404
1682
  change_amount=skill_cost_info.fee_dev_amount,
1405
1683
  credit_type=CreditType.REWARD,
1684
+ free_amount=fee_dev_free_amount,
1685
+ reward_amount=fee_dev_reward_amount,
1686
+ permanent_amount=fee_dev_permanent_amount,
1406
1687
  )
1407
1688
  session.add(dev_tx)
1408
1689
 
@@ -1416,6 +1697,9 @@ async def expense_skill(
1416
1697
  credit_debit=CreditDebit.CREDIT,
1417
1698
  change_amount=skill_cost_info.fee_agent_amount,
1418
1699
  credit_type=credit_type,
1700
+ free_amount=fee_agent_free_amount,
1701
+ reward_amount=fee_agent_reward_amount,
1702
+ permanent_amount=fee_agent_permanent_amount,
1419
1703
  )
1420
1704
  session.add(agent_tx)
1421
1705
 
@@ -1447,7 +1731,7 @@ async def refill_free_credits_for_account(
1447
1731
  # If adding refill_amount would exceed free_quota, only add what's needed to reach free_quota
1448
1732
  amount_to_add = min(
1449
1733
  account.refill_amount, account.free_quota - account.free_credits
1450
- )
1734
+ ).quantize(FOURPLACES, rounding=ROUND_HALF_UP)
1451
1735
 
1452
1736
  if amount_to_add <= Decimal("0"):
1453
1737
  return # Nothing to add
@@ -1460,8 +1744,7 @@ async def refill_free_credits_for_account(
1460
1744
  session=session,
1461
1745
  owner_type=account.owner_type,
1462
1746
  owner_id=account.owner_id,
1463
- amount=amount_to_add,
1464
- credit_type=CreditType.FREE,
1747
+ amount_details={CreditType.FREE: amount_to_add},
1465
1748
  event_id=event_id,
1466
1749
  )
1467
1750
 
@@ -1492,6 +1775,9 @@ async def refill_free_credits_for_account(
1492
1775
  + updated_account.reward_credits,
1493
1776
  base_amount=amount_to_add,
1494
1777
  base_original_amount=amount_to_add,
1778
+ base_free_amount=amount_to_add,
1779
+ base_reward_amount=Decimal("0"),
1780
+ base_permanent_amount=Decimal("0"),
1495
1781
  free_amount=amount_to_add, # Set free_amount since this is a free credit refill
1496
1782
  reward_amount=Decimal("0"), # No reward credits involved
1497
1783
  permanent_amount=Decimal("0"), # No permanent credits involved
@@ -1511,6 +1797,9 @@ async def refill_free_credits_for_account(
1511
1797
  credit_debit=CreditDebit.CREDIT,
1512
1798
  change_amount=amount_to_add,
1513
1799
  credit_type=CreditType.FREE,
1800
+ free_amount=amount_to_add,
1801
+ reward_amount=Decimal("0"),
1802
+ permanent_amount=Decimal("0"),
1514
1803
  )
1515
1804
  session.add(user_tx)
1516
1805
 
@@ -1523,6 +1812,9 @@ async def refill_free_credits_for_account(
1523
1812
  credit_debit=CreditDebit.DEBIT,
1524
1813
  change_amount=amount_to_add,
1525
1814
  credit_type=CreditType.FREE,
1815
+ free_amount=amount_to_add,
1816
+ reward_amount=Decimal("0"),
1817
+ permanent_amount=Decimal("0"),
1526
1818
  )
1527
1819
  session.add(platform_tx)
1528
1820
 
@@ -1636,38 +1928,12 @@ async def expense_summarize(
1636
1928
  session=session, id=agent.id, amount=details.get(CreditType.FREE)
1637
1929
  )
1638
1930
 
1639
- # 3. Update fee account - add credits
1640
- memory_account = await CreditAccount.income_in_session(
1641
- session=session,
1642
- owner_type=OwnerType.PLATFORM,
1643
- owner_id=DEFAULT_PLATFORM_ACCOUNT_MEMORY,
1644
- credit_type=CreditType.PERMANENT,
1645
- amount=base_amount,
1646
- event_id=event_id,
1647
- )
1648
- platform_fee_account = await CreditAccount.income_in_session(
1649
- session=session,
1650
- owner_type=OwnerType.PLATFORM,
1651
- owner_id=DEFAULT_PLATFORM_ACCOUNT_FEE,
1652
- credit_type=CreditType.PERMANENT,
1653
- amount=fee_platform_amount,
1654
- event_id=event_id,
1655
- )
1656
- if fee_agent_amount > 0:
1657
- agent_account = await CreditAccount.income_in_session(
1658
- session=session,
1659
- owner_type=OwnerType.AGENT,
1660
- owner_id=agent.id,
1661
- credit_type=CreditType.REWARD,
1662
- amount=fee_agent_amount,
1663
- event_id=event_id,
1664
- )
1665
-
1666
- # 4. Create credit event record
1931
+ # 3. Calculate fee amounts by credit type before income_in_session calls
1667
1932
  # Set the appropriate credit amount field based on credit type
1668
1933
  free_amount = details.get(CreditType.FREE, Decimal("0"))
1669
1934
  reward_amount = details.get(CreditType.REWARD, Decimal("0"))
1670
1935
  permanent_amount = details.get(CreditType.PERMANENT, Decimal("0"))
1936
+
1671
1937
  if CreditType.PERMANENT in details:
1672
1938
  credit_type = CreditType.PERMANENT
1673
1939
  elif CreditType.REWARD in details:
@@ -1719,6 +1985,55 @@ async def expense_summarize(
1719
1985
  fee_agent_amount - fee_agent_free_amount - fee_agent_reward_amount
1720
1986
  ).quantize(FOURPLACES, rounding=ROUND_HALF_UP)
1721
1987
 
1988
+ # Calculate base amounts by credit type using subtraction method
1989
+ base_free_amount = free_amount - fee_platform_free_amount - fee_agent_free_amount
1990
+
1991
+ base_reward_amount = (
1992
+ reward_amount - fee_platform_reward_amount - fee_agent_reward_amount
1993
+ )
1994
+
1995
+ base_permanent_amount = (
1996
+ permanent_amount - fee_platform_permanent_amount - fee_agent_permanent_amount
1997
+ )
1998
+
1999
+ # 4. Update fee account - add credits
2000
+ memory_account = await CreditAccount.income_in_session(
2001
+ session=session,
2002
+ owner_type=OwnerType.PLATFORM,
2003
+ owner_id=DEFAULT_PLATFORM_ACCOUNT_MEMORY,
2004
+ amount_details={
2005
+ CreditType.FREE: base_free_amount,
2006
+ CreditType.REWARD: base_reward_amount,
2007
+ CreditType.PERMANENT: base_permanent_amount,
2008
+ },
2009
+ event_id=event_id,
2010
+ )
2011
+ platform_fee_account = await CreditAccount.income_in_session(
2012
+ session=session,
2013
+ owner_type=OwnerType.PLATFORM,
2014
+ owner_id=DEFAULT_PLATFORM_ACCOUNT_FEE,
2015
+ amount_details={
2016
+ CreditType.FREE: fee_platform_free_amount,
2017
+ CreditType.REWARD: fee_platform_reward_amount,
2018
+ CreditType.PERMANENT: fee_platform_permanent_amount,
2019
+ },
2020
+ event_id=event_id,
2021
+ )
2022
+ if fee_agent_amount > 0:
2023
+ agent_account = await CreditAccount.income_in_session(
2024
+ session=session,
2025
+ owner_type=OwnerType.AGENT,
2026
+ owner_id=agent.id,
2027
+ amount_details={
2028
+ CreditType.FREE: fee_agent_free_amount,
2029
+ CreditType.REWARD: fee_agent_reward_amount,
2030
+ CreditType.PERMANENT: fee_agent_permanent_amount,
2031
+ },
2032
+ event_id=event_id,
2033
+ )
2034
+
2035
+ # 5. Create credit event record
2036
+
1722
2037
  # Get agent wallet address
1723
2038
  agent_data = await AgentData.get(agent.id)
1724
2039
  agent_wallet_address = agent_data.evm_wallet_address if agent_data else None
@@ -1744,6 +2059,9 @@ async def expense_summarize(
1744
2059
  base_amount=base_amount,
1745
2060
  base_original_amount=base_original_amount,
1746
2061
  base_llm_amount=base_llm_amount,
2062
+ base_free_amount=base_free_amount,
2063
+ base_reward_amount=base_reward_amount,
2064
+ base_permanent_amount=base_permanent_amount,
1747
2065
  fee_platform_amount=fee_platform_amount,
1748
2066
  fee_platform_free_amount=fee_platform_free_amount,
1749
2067
  fee_platform_reward_amount=fee_platform_reward_amount,
@@ -1769,6 +2087,9 @@ async def expense_summarize(
1769
2087
  credit_debit=CreditDebit.DEBIT,
1770
2088
  change_amount=total_amount,
1771
2089
  credit_type=credit_type,
2090
+ free_amount=free_amount,
2091
+ reward_amount=reward_amount,
2092
+ permanent_amount=permanent_amount,
1772
2093
  )
1773
2094
  session.add(user_tx)
1774
2095
 
@@ -1781,6 +2102,9 @@ async def expense_summarize(
1781
2102
  credit_debit=CreditDebit.CREDIT,
1782
2103
  change_amount=base_amount,
1783
2104
  credit_type=credit_type,
2105
+ free_amount=base_free_amount,
2106
+ reward_amount=base_reward_amount,
2107
+ permanent_amount=base_permanent_amount,
1784
2108
  )
1785
2109
  session.add(memory_tx)
1786
2110
 
@@ -1793,6 +2117,9 @@ async def expense_summarize(
1793
2117
  credit_debit=CreditDebit.CREDIT,
1794
2118
  change_amount=fee_platform_amount,
1795
2119
  credit_type=credit_type,
2120
+ free_amount=fee_platform_free_amount,
2121
+ reward_amount=fee_platform_reward_amount,
2122
+ permanent_amount=fee_platform_permanent_amount,
1796
2123
  )
1797
2124
  session.add(platform_tx)
1798
2125
 
@@ -1806,6 +2133,9 @@ async def expense_summarize(
1806
2133
  credit_debit=CreditDebit.CREDIT,
1807
2134
  change_amount=fee_agent_amount,
1808
2135
  credit_type=CreditType.REWARD,
2136
+ free_amount=fee_agent_free_amount,
2137
+ reward_amount=fee_agent_reward_amount,
2138
+ permanent_amount=fee_agent_permanent_amount,
1809
2139
  )
1810
2140
  session.add(agent_tx)
1811
2141