intentkit 0.5.0__py3-none-any.whl → 0.5.2__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (366) hide show
  1. intentkit/__init__.py +17 -0
  2. intentkit/abstracts/__init__.py +0 -0
  3. intentkit/abstracts/agent.py +60 -0
  4. intentkit/abstracts/api.py +4 -0
  5. intentkit/abstracts/engine.py +38 -0
  6. intentkit/abstracts/exception.py +9 -0
  7. intentkit/abstracts/graph.py +25 -0
  8. intentkit/abstracts/skill.py +129 -0
  9. intentkit/abstracts/twitter.py +54 -0
  10. intentkit/clients/__init__.py +14 -0
  11. intentkit/clients/cdp.py +53 -0
  12. intentkit/clients/twitter.py +445 -0
  13. intentkit/config/__init__.py +0 -0
  14. intentkit/config/config.py +164 -0
  15. intentkit/core/__init__.py +0 -0
  16. intentkit/core/agent.py +191 -0
  17. intentkit/core/api.py +40 -0
  18. intentkit/core/client.py +45 -0
  19. intentkit/core/credit.py +1767 -0
  20. intentkit/core/engine.py +1018 -0
  21. intentkit/core/node.py +223 -0
  22. intentkit/core/prompt.py +58 -0
  23. intentkit/core/skill.py +124 -0
  24. intentkit/models/agent.py +1689 -0
  25. intentkit/models/agent_data.py +810 -0
  26. intentkit/models/agent_schema.json +733 -0
  27. intentkit/models/app_setting.py +156 -0
  28. intentkit/models/base.py +9 -0
  29. intentkit/models/chat.py +581 -0
  30. intentkit/models/conversation.py +286 -0
  31. intentkit/models/credit.py +1406 -0
  32. intentkit/models/db.py +120 -0
  33. intentkit/models/db_mig.py +102 -0
  34. intentkit/models/generator.py +347 -0
  35. intentkit/models/llm.py +746 -0
  36. intentkit/models/redis.py +132 -0
  37. intentkit/models/skill.py +466 -0
  38. intentkit/models/user.py +243 -0
  39. intentkit/skills/__init__.py +12 -0
  40. intentkit/skills/acolyt/__init__.py +83 -0
  41. intentkit/skills/acolyt/acolyt.jpg +0 -0
  42. intentkit/skills/acolyt/ask.py +128 -0
  43. intentkit/skills/acolyt/base.py +28 -0
  44. intentkit/skills/acolyt/schema.json +89 -0
  45. intentkit/skills/aixbt/README.md +71 -0
  46. intentkit/skills/aixbt/__init__.py +73 -0
  47. intentkit/skills/aixbt/aixbt.jpg +0 -0
  48. intentkit/skills/aixbt/base.py +21 -0
  49. intentkit/skills/aixbt/projects.py +153 -0
  50. intentkit/skills/aixbt/schema.json +99 -0
  51. intentkit/skills/allora/__init__.py +83 -0
  52. intentkit/skills/allora/allora.jpeg +0 -0
  53. intentkit/skills/allora/base.py +28 -0
  54. intentkit/skills/allora/price.py +130 -0
  55. intentkit/skills/allora/schema.json +89 -0
  56. intentkit/skills/base.py +174 -0
  57. intentkit/skills/carv/README.md +95 -0
  58. intentkit/skills/carv/__init__.py +121 -0
  59. intentkit/skills/carv/base.py +183 -0
  60. intentkit/skills/carv/carv.webp +0 -0
  61. intentkit/skills/carv/fetch_news.py +92 -0
  62. intentkit/skills/carv/onchain_query.py +164 -0
  63. intentkit/skills/carv/schema.json +137 -0
  64. intentkit/skills/carv/token_info_and_price.py +110 -0
  65. intentkit/skills/cdp/__init__.py +137 -0
  66. intentkit/skills/cdp/base.py +21 -0
  67. intentkit/skills/cdp/cdp.png +0 -0
  68. intentkit/skills/cdp/get_balance.py +81 -0
  69. intentkit/skills/cdp/schema.json +473 -0
  70. intentkit/skills/chainlist/README.md +38 -0
  71. intentkit/skills/chainlist/__init__.py +54 -0
  72. intentkit/skills/chainlist/base.py +21 -0
  73. intentkit/skills/chainlist/chain_lookup.py +208 -0
  74. intentkit/skills/chainlist/chainlist.png +0 -0
  75. intentkit/skills/chainlist/schema.json +47 -0
  76. intentkit/skills/common/__init__.py +82 -0
  77. intentkit/skills/common/base.py +21 -0
  78. intentkit/skills/common/common.jpg +0 -0
  79. intentkit/skills/common/current_time.py +84 -0
  80. intentkit/skills/common/schema.json +57 -0
  81. intentkit/skills/cookiefun/README.md +121 -0
  82. intentkit/skills/cookiefun/__init__.py +78 -0
  83. intentkit/skills/cookiefun/base.py +41 -0
  84. intentkit/skills/cookiefun/constants.py +18 -0
  85. intentkit/skills/cookiefun/cookiefun.png +0 -0
  86. intentkit/skills/cookiefun/get_account_details.py +171 -0
  87. intentkit/skills/cookiefun/get_account_feed.py +282 -0
  88. intentkit/skills/cookiefun/get_account_smart_followers.py +181 -0
  89. intentkit/skills/cookiefun/get_sectors.py +128 -0
  90. intentkit/skills/cookiefun/schema.json +155 -0
  91. intentkit/skills/cookiefun/search_accounts.py +225 -0
  92. intentkit/skills/cryptocompare/__init__.py +130 -0
  93. intentkit/skills/cryptocompare/api.py +159 -0
  94. intentkit/skills/cryptocompare/base.py +303 -0
  95. intentkit/skills/cryptocompare/cryptocompare.png +0 -0
  96. intentkit/skills/cryptocompare/fetch_news.py +96 -0
  97. intentkit/skills/cryptocompare/fetch_price.py +99 -0
  98. intentkit/skills/cryptocompare/fetch_top_exchanges.py +113 -0
  99. intentkit/skills/cryptocompare/fetch_top_market_cap.py +109 -0
  100. intentkit/skills/cryptocompare/fetch_top_volume.py +108 -0
  101. intentkit/skills/cryptocompare/fetch_trading_signals.py +107 -0
  102. intentkit/skills/cryptocompare/schema.json +168 -0
  103. intentkit/skills/cryptopanic/__init__.py +108 -0
  104. intentkit/skills/cryptopanic/base.py +51 -0
  105. intentkit/skills/cryptopanic/cryptopanic.png +0 -0
  106. intentkit/skills/cryptopanic/fetch_crypto_news.py +153 -0
  107. intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +136 -0
  108. intentkit/skills/cryptopanic/schema.json +103 -0
  109. intentkit/skills/dapplooker/README.md +92 -0
  110. intentkit/skills/dapplooker/__init__.py +83 -0
  111. intentkit/skills/dapplooker/base.py +26 -0
  112. intentkit/skills/dapplooker/dapplooker.jpg +0 -0
  113. intentkit/skills/dapplooker/dapplooker_token_data.py +476 -0
  114. intentkit/skills/dapplooker/schema.json +91 -0
  115. intentkit/skills/defillama/__init__.py +323 -0
  116. intentkit/skills/defillama/api.py +315 -0
  117. intentkit/skills/defillama/base.py +135 -0
  118. intentkit/skills/defillama/coins/__init__.py +0 -0
  119. intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +116 -0
  120. intentkit/skills/defillama/coins/fetch_block.py +98 -0
  121. intentkit/skills/defillama/coins/fetch_current_prices.py +105 -0
  122. intentkit/skills/defillama/coins/fetch_first_price.py +100 -0
  123. intentkit/skills/defillama/coins/fetch_historical_prices.py +110 -0
  124. intentkit/skills/defillama/coins/fetch_price_chart.py +109 -0
  125. intentkit/skills/defillama/coins/fetch_price_percentage.py +93 -0
  126. intentkit/skills/defillama/config/__init__.py +0 -0
  127. intentkit/skills/defillama/config/chains.py +433 -0
  128. intentkit/skills/defillama/defillama.jpeg +0 -0
  129. intentkit/skills/defillama/fees/__init__.py +0 -0
  130. intentkit/skills/defillama/fees/fetch_fees_overview.py +130 -0
  131. intentkit/skills/defillama/schema.json +383 -0
  132. intentkit/skills/defillama/stablecoins/__init__.py +0 -0
  133. intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +100 -0
  134. intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +129 -0
  135. intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +83 -0
  136. intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +126 -0
  137. intentkit/skills/defillama/tests/__init__.py +0 -0
  138. intentkit/skills/defillama/tests/api_integration.test.py +192 -0
  139. intentkit/skills/defillama/tests/api_unit.test.py +583 -0
  140. intentkit/skills/defillama/tvl/__init__.py +0 -0
  141. intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +106 -0
  142. intentkit/skills/defillama/tvl/fetch_chains.py +107 -0
  143. intentkit/skills/defillama/tvl/fetch_historical_tvl.py +91 -0
  144. intentkit/skills/defillama/tvl/fetch_protocol.py +207 -0
  145. intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +93 -0
  146. intentkit/skills/defillama/tvl/fetch_protocols.py +196 -0
  147. intentkit/skills/defillama/volumes/__init__.py +0 -0
  148. intentkit/skills/defillama/volumes/fetch_dex_overview.py +157 -0
  149. intentkit/skills/defillama/volumes/fetch_dex_summary.py +123 -0
  150. intentkit/skills/defillama/volumes/fetch_options_overview.py +131 -0
  151. intentkit/skills/defillama/yields/__init__.py +0 -0
  152. intentkit/skills/defillama/yields/fetch_pool_chart.py +100 -0
  153. intentkit/skills/defillama/yields/fetch_pools.py +126 -0
  154. intentkit/skills/dexscreener/__init__.py +93 -0
  155. intentkit/skills/dexscreener/base.py +133 -0
  156. intentkit/skills/dexscreener/dexscreener.png +0 -0
  157. intentkit/skills/dexscreener/model/__init__.py +0 -0
  158. intentkit/skills/dexscreener/model/search_token_response.py +82 -0
  159. intentkit/skills/dexscreener/schema.json +48 -0
  160. intentkit/skills/dexscreener/search_token.py +321 -0
  161. intentkit/skills/dune_analytics/__init__.py +103 -0
  162. intentkit/skills/dune_analytics/base.py +46 -0
  163. intentkit/skills/dune_analytics/dune.png +0 -0
  164. intentkit/skills/dune_analytics/fetch_kol_buys.py +128 -0
  165. intentkit/skills/dune_analytics/fetch_nation_metrics.py +237 -0
  166. intentkit/skills/dune_analytics/schema.json +99 -0
  167. intentkit/skills/elfa/README.md +100 -0
  168. intentkit/skills/elfa/__init__.py +123 -0
  169. intentkit/skills/elfa/base.py +28 -0
  170. intentkit/skills/elfa/elfa.jpg +0 -0
  171. intentkit/skills/elfa/mention.py +504 -0
  172. intentkit/skills/elfa/schema.json +153 -0
  173. intentkit/skills/elfa/stats.py +118 -0
  174. intentkit/skills/elfa/tokens.py +126 -0
  175. intentkit/skills/enso/README.md +75 -0
  176. intentkit/skills/enso/__init__.py +114 -0
  177. intentkit/skills/enso/abi/__init__.py +0 -0
  178. intentkit/skills/enso/abi/approval.py +279 -0
  179. intentkit/skills/enso/abi/erc20.py +14 -0
  180. intentkit/skills/enso/abi/route.py +129 -0
  181. intentkit/skills/enso/base.py +44 -0
  182. intentkit/skills/enso/best_yield.py +286 -0
  183. intentkit/skills/enso/enso.jpg +0 -0
  184. intentkit/skills/enso/networks.py +105 -0
  185. intentkit/skills/enso/prices.py +93 -0
  186. intentkit/skills/enso/route.py +300 -0
  187. intentkit/skills/enso/schema.json +212 -0
  188. intentkit/skills/enso/tokens.py +223 -0
  189. intentkit/skills/enso/wallet.py +381 -0
  190. intentkit/skills/github/README.md +63 -0
  191. intentkit/skills/github/__init__.py +54 -0
  192. intentkit/skills/github/base.py +21 -0
  193. intentkit/skills/github/github.jpg +0 -0
  194. intentkit/skills/github/github_search.py +183 -0
  195. intentkit/skills/github/schema.json +59 -0
  196. intentkit/skills/heurist/__init__.py +143 -0
  197. intentkit/skills/heurist/base.py +26 -0
  198. intentkit/skills/heurist/heurist.png +0 -0
  199. intentkit/skills/heurist/image_generation_animagine_xl.py +162 -0
  200. intentkit/skills/heurist/image_generation_arthemy_comics.py +162 -0
  201. intentkit/skills/heurist/image_generation_arthemy_real.py +162 -0
  202. intentkit/skills/heurist/image_generation_braindance.py +162 -0
  203. intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +162 -0
  204. intentkit/skills/heurist/image_generation_flux_1_dev.py +162 -0
  205. intentkit/skills/heurist/image_generation_sdxl.py +161 -0
  206. intentkit/skills/heurist/schema.json +196 -0
  207. intentkit/skills/lifi/README.md +294 -0
  208. intentkit/skills/lifi/__init__.py +141 -0
  209. intentkit/skills/lifi/base.py +21 -0
  210. intentkit/skills/lifi/lifi.png +0 -0
  211. intentkit/skills/lifi/schema.json +89 -0
  212. intentkit/skills/lifi/token_execute.py +472 -0
  213. intentkit/skills/lifi/token_quote.py +190 -0
  214. intentkit/skills/lifi/utils.py +656 -0
  215. intentkit/skills/moralis/README.md +490 -0
  216. intentkit/skills/moralis/__init__.py +110 -0
  217. intentkit/skills/moralis/api.py +281 -0
  218. intentkit/skills/moralis/base.py +55 -0
  219. intentkit/skills/moralis/fetch_chain_portfolio.py +191 -0
  220. intentkit/skills/moralis/fetch_nft_portfolio.py +284 -0
  221. intentkit/skills/moralis/fetch_solana_portfolio.py +331 -0
  222. intentkit/skills/moralis/fetch_wallet_portfolio.py +301 -0
  223. intentkit/skills/moralis/moralis.png +0 -0
  224. intentkit/skills/moralis/schema.json +156 -0
  225. intentkit/skills/moralis/tests/__init__.py +0 -0
  226. intentkit/skills/moralis/tests/test_wallet.py +511 -0
  227. intentkit/skills/nation/__init__.py +62 -0
  228. intentkit/skills/nation/base.py +31 -0
  229. intentkit/skills/nation/nation.png +0 -0
  230. intentkit/skills/nation/nft_check.py +106 -0
  231. intentkit/skills/nation/schema.json +58 -0
  232. intentkit/skills/openai/__init__.py +107 -0
  233. intentkit/skills/openai/base.py +32 -0
  234. intentkit/skills/openai/dalle_image_generation.py +128 -0
  235. intentkit/skills/openai/gpt_image_generation.py +152 -0
  236. intentkit/skills/openai/gpt_image_to_image.py +186 -0
  237. intentkit/skills/openai/image_to_text.py +126 -0
  238. intentkit/skills/openai/openai.png +0 -0
  239. intentkit/skills/openai/schema.json +139 -0
  240. intentkit/skills/portfolio/README.md +55 -0
  241. intentkit/skills/portfolio/__init__.py +151 -0
  242. intentkit/skills/portfolio/base.py +107 -0
  243. intentkit/skills/portfolio/constants.py +9 -0
  244. intentkit/skills/portfolio/moralis.png +0 -0
  245. intentkit/skills/portfolio/schema.json +237 -0
  246. intentkit/skills/portfolio/token_balances.py +155 -0
  247. intentkit/skills/portfolio/wallet_approvals.py +102 -0
  248. intentkit/skills/portfolio/wallet_defi_positions.py +80 -0
  249. intentkit/skills/portfolio/wallet_history.py +155 -0
  250. intentkit/skills/portfolio/wallet_net_worth.py +112 -0
  251. intentkit/skills/portfolio/wallet_nfts.py +139 -0
  252. intentkit/skills/portfolio/wallet_profitability.py +101 -0
  253. intentkit/skills/portfolio/wallet_profitability_summary.py +91 -0
  254. intentkit/skills/portfolio/wallet_stats.py +79 -0
  255. intentkit/skills/portfolio/wallet_swaps.py +147 -0
  256. intentkit/skills/skills.toml +103 -0
  257. intentkit/skills/slack/__init__.py +98 -0
  258. intentkit/skills/slack/base.py +55 -0
  259. intentkit/skills/slack/get_channel.py +109 -0
  260. intentkit/skills/slack/get_message.py +136 -0
  261. intentkit/skills/slack/schedule_message.py +92 -0
  262. intentkit/skills/slack/schema.json +135 -0
  263. intentkit/skills/slack/send_message.py +81 -0
  264. intentkit/skills/slack/slack.jpg +0 -0
  265. intentkit/skills/system/__init__.py +90 -0
  266. intentkit/skills/system/base.py +22 -0
  267. intentkit/skills/system/read_agent_api_key.py +87 -0
  268. intentkit/skills/system/regenerate_agent_api_key.py +77 -0
  269. intentkit/skills/system/schema.json +53 -0
  270. intentkit/skills/system/system.svg +76 -0
  271. intentkit/skills/tavily/README.md +86 -0
  272. intentkit/skills/tavily/__init__.py +91 -0
  273. intentkit/skills/tavily/base.py +27 -0
  274. intentkit/skills/tavily/schema.json +119 -0
  275. intentkit/skills/tavily/tavily.jpg +0 -0
  276. intentkit/skills/tavily/tavily_extract.py +147 -0
  277. intentkit/skills/tavily/tavily_search.py +139 -0
  278. intentkit/skills/token/README.md +89 -0
  279. intentkit/skills/token/__init__.py +107 -0
  280. intentkit/skills/token/base.py +154 -0
  281. intentkit/skills/token/constants.py +9 -0
  282. intentkit/skills/token/erc20_transfers.py +145 -0
  283. intentkit/skills/token/moralis.png +0 -0
  284. intentkit/skills/token/schema.json +141 -0
  285. intentkit/skills/token/token_analytics.py +81 -0
  286. intentkit/skills/token/token_price.py +132 -0
  287. intentkit/skills/token/token_search.py +121 -0
  288. intentkit/skills/twitter/__init__.py +146 -0
  289. intentkit/skills/twitter/base.py +68 -0
  290. intentkit/skills/twitter/follow_user.py +69 -0
  291. intentkit/skills/twitter/get_mentions.py +124 -0
  292. intentkit/skills/twitter/get_timeline.py +111 -0
  293. intentkit/skills/twitter/get_user_by_username.py +84 -0
  294. intentkit/skills/twitter/get_user_tweets.py +123 -0
  295. intentkit/skills/twitter/like_tweet.py +65 -0
  296. intentkit/skills/twitter/post_tweet.py +90 -0
  297. intentkit/skills/twitter/reply_tweet.py +98 -0
  298. intentkit/skills/twitter/retweet.py +76 -0
  299. intentkit/skills/twitter/schema.json +258 -0
  300. intentkit/skills/twitter/search_tweets.py +115 -0
  301. intentkit/skills/twitter/twitter.png +0 -0
  302. intentkit/skills/unrealspeech/__init__.py +55 -0
  303. intentkit/skills/unrealspeech/base.py +21 -0
  304. intentkit/skills/unrealspeech/schema.json +100 -0
  305. intentkit/skills/unrealspeech/text_to_speech.py +177 -0
  306. intentkit/skills/unrealspeech/unrealspeech.jpg +0 -0
  307. intentkit/skills/venice_audio/__init__.py +106 -0
  308. intentkit/skills/venice_audio/base.py +119 -0
  309. intentkit/skills/venice_audio/input.py +41 -0
  310. intentkit/skills/venice_audio/schema.json +152 -0
  311. intentkit/skills/venice_audio/venice_audio.py +240 -0
  312. intentkit/skills/venice_audio/venice_logo.jpg +0 -0
  313. intentkit/skills/venice_image/README.md +119 -0
  314. intentkit/skills/venice_image/__init__.py +154 -0
  315. intentkit/skills/venice_image/api.py +138 -0
  316. intentkit/skills/venice_image/base.py +188 -0
  317. intentkit/skills/venice_image/config.py +35 -0
  318. intentkit/skills/venice_image/image_enhance/README.md +119 -0
  319. intentkit/skills/venice_image/image_enhance/__init__.py +0 -0
  320. intentkit/skills/venice_image/image_enhance/image_enhance.py +80 -0
  321. intentkit/skills/venice_image/image_enhance/image_enhance_base.py +23 -0
  322. intentkit/skills/venice_image/image_enhance/image_enhance_input.py +40 -0
  323. intentkit/skills/venice_image/image_generation/README.md +144 -0
  324. intentkit/skills/venice_image/image_generation/__init__.py +0 -0
  325. intentkit/skills/venice_image/image_generation/image_generation_base.py +117 -0
  326. intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -0
  327. intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -0
  328. intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -0
  329. intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -0
  330. intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -0
  331. intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -0
  332. intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -0
  333. intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -0
  334. intentkit/skills/venice_image/image_upscale/README.md +111 -0
  335. intentkit/skills/venice_image/image_upscale/__init__.py +0 -0
  336. intentkit/skills/venice_image/image_upscale/image_upscale.py +90 -0
  337. intentkit/skills/venice_image/image_upscale/image_upscale_base.py +23 -0
  338. intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -0
  339. intentkit/skills/venice_image/image_vision/README.md +112 -0
  340. intentkit/skills/venice_image/image_vision/__init__.py +0 -0
  341. intentkit/skills/venice_image/image_vision/image_vision.py +100 -0
  342. intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -0
  343. intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -0
  344. intentkit/skills/venice_image/schema.json +267 -0
  345. intentkit/skills/venice_image/utils.py +78 -0
  346. intentkit/skills/venice_image/venice_image.jpg +0 -0
  347. intentkit/skills/web_scraper/README.md +82 -0
  348. intentkit/skills/web_scraper/__init__.py +92 -0
  349. intentkit/skills/web_scraper/base.py +21 -0
  350. intentkit/skills/web_scraper/langchain.png +0 -0
  351. intentkit/skills/web_scraper/schema.json +115 -0
  352. intentkit/skills/web_scraper/scrape_and_index.py +327 -0
  353. intentkit/utils/__init__.py +1 -0
  354. intentkit/utils/chain.py +436 -0
  355. intentkit/utils/error.py +134 -0
  356. intentkit/utils/logging.py +70 -0
  357. intentkit/utils/middleware.py +61 -0
  358. intentkit/utils/random.py +16 -0
  359. intentkit/utils/s3.py +267 -0
  360. intentkit/utils/slack_alert.py +79 -0
  361. intentkit/utils/tx.py +37 -0
  362. {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/METADATA +1 -1
  363. intentkit-0.5.2.dist-info/RECORD +365 -0
  364. intentkit-0.5.0.dist-info/RECORD +0 -4
  365. {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/WHEEL +0 -0
  366. {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,810 @@
1
+ import logging
2
+ from datetime import datetime, timezone
3
+ from decimal import Decimal
4
+ from typing import Annotated, Any, Dict, Optional
5
+
6
+ from fastapi import HTTPException
7
+ from intentkit.models.base import Base
8
+ from intentkit.models.db import get_session
9
+ from pydantic import BaseModel, ConfigDict
10
+ from pydantic import Field as PydanticField
11
+ from sqlalchemy import (
12
+ BigInteger,
13
+ Boolean,
14
+ Column,
15
+ DateTime,
16
+ Numeric,
17
+ String,
18
+ func,
19
+ select,
20
+ )
21
+ from sqlalchemy.dialects.postgresql import JSON, JSONB
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class AgentDataTable(Base):
27
+ """Agent data model for database storage of additional data related to the agent."""
28
+
29
+ __tablename__ = "agent_data"
30
+
31
+ id = Column(String, primary_key=True, comment="Same as Agent.id")
32
+ cdp_wallet_data = Column(String, nullable=True, comment="CDP wallet data")
33
+ crossmint_wallet_data = Column(
34
+ JSON().with_variant(JSONB(), "postgresql"),
35
+ nullable=True,
36
+ comment="Crossmint wallet information",
37
+ )
38
+ twitter_id = Column(String, nullable=True, comment="Twitter user ID")
39
+ twitter_username = Column(String, nullable=True, comment="Twitter username")
40
+ twitter_name = Column(String, nullable=True, comment="Twitter display name")
41
+ twitter_access_token = Column(String, nullable=True, comment="Twitter access token")
42
+ twitter_access_token_expires_at = Column(
43
+ DateTime(timezone=True),
44
+ nullable=True,
45
+ comment="Twitter access token expiration time",
46
+ )
47
+ twitter_refresh_token = Column(
48
+ String, nullable=True, comment="Twitter refresh token"
49
+ )
50
+ twitter_self_key_refreshed_at = Column(
51
+ DateTime(timezone=True),
52
+ nullable=True,
53
+ comment="Twitter self-key userinfo last refresh time",
54
+ )
55
+ twitter_is_verified = Column(
56
+ Boolean,
57
+ nullable=False,
58
+ default=False,
59
+ comment="Whether the Twitter account is verified",
60
+ )
61
+ telegram_id = Column(String, nullable=True, comment="Telegram user ID")
62
+ telegram_username = Column(String, nullable=True, comment="Telegram username")
63
+ telegram_name = Column(String, nullable=True, comment="Telegram display name")
64
+ error_message = Column(String, nullable=True, comment="Last error message")
65
+ api_key = Column(
66
+ String, nullable=True, unique=True, comment="API key for the agent"
67
+ )
68
+ api_key_public = Column(
69
+ String, nullable=True, unique=True, comment="Public API key for the agent"
70
+ )
71
+ created_at = Column(
72
+ DateTime(timezone=True),
73
+ nullable=False,
74
+ server_default=func.now(),
75
+ comment="Timestamp when the agent data was created",
76
+ )
77
+ updated_at = Column(
78
+ DateTime(timezone=True),
79
+ nullable=False,
80
+ server_default=func.now(),
81
+ onupdate=lambda: datetime.now(timezone.utc),
82
+ comment="Timestamp when the agent data was last updated",
83
+ )
84
+
85
+
86
+ class AgentData(BaseModel):
87
+ """Agent data model for storing additional data related to the agent."""
88
+
89
+ model_config = ConfigDict(from_attributes=True)
90
+
91
+ id: Annotated[
92
+ str,
93
+ PydanticField(
94
+ description="Same as Agent.id",
95
+ ),
96
+ ]
97
+ cdp_wallet_data: Annotated[
98
+ Optional[str],
99
+ PydanticField(
100
+ default=None,
101
+ description="CDP wallet data",
102
+ ),
103
+ ]
104
+ crossmint_wallet_data: Annotated[
105
+ Optional[dict],
106
+ PydanticField(
107
+ default=None,
108
+ description="Crossmint wallet information",
109
+ ),
110
+ ]
111
+ twitter_id: Annotated[
112
+ Optional[str],
113
+ PydanticField(
114
+ default=None,
115
+ description="Twitter user ID",
116
+ ),
117
+ ]
118
+ twitter_username: Annotated[
119
+ Optional[str],
120
+ PydanticField(
121
+ default=None,
122
+ description="Twitter username",
123
+ ),
124
+ ]
125
+ twitter_name: Annotated[
126
+ Optional[str],
127
+ PydanticField(
128
+ default=None,
129
+ description="Twitter display name",
130
+ ),
131
+ ]
132
+ twitter_access_token: Annotated[
133
+ Optional[str],
134
+ PydanticField(
135
+ default=None,
136
+ description="Twitter access token",
137
+ ),
138
+ ]
139
+ twitter_access_token_expires_at: Annotated[
140
+ Optional[datetime],
141
+ PydanticField(
142
+ default=None,
143
+ description="Twitter access token expiration time",
144
+ ),
145
+ ]
146
+ twitter_refresh_token: Annotated[
147
+ Optional[str],
148
+ PydanticField(
149
+ default=None,
150
+ description="Twitter refresh token",
151
+ ),
152
+ ]
153
+ twitter_self_key_refreshed_at: Annotated[
154
+ Optional[datetime],
155
+ PydanticField(
156
+ default=None,
157
+ description="Twitter self-key userinfo last refresh time",
158
+ ),
159
+ ]
160
+ twitter_is_verified: Annotated[
161
+ bool,
162
+ PydanticField(
163
+ default=False,
164
+ description="Whether the Twitter account is verified",
165
+ ),
166
+ ]
167
+ telegram_id: Annotated[
168
+ Optional[str],
169
+ PydanticField(
170
+ default=None,
171
+ description="Telegram user ID",
172
+ ),
173
+ ]
174
+ telegram_username: Annotated[
175
+ Optional[str],
176
+ PydanticField(
177
+ default=None,
178
+ description="Telegram username",
179
+ ),
180
+ ]
181
+ telegram_name: Annotated[
182
+ Optional[str],
183
+ PydanticField(
184
+ default=None,
185
+ description="Telegram display name",
186
+ ),
187
+ ]
188
+ error_message: Annotated[
189
+ Optional[str],
190
+ PydanticField(
191
+ default=None,
192
+ description="Last error message",
193
+ ),
194
+ ]
195
+ api_key: Annotated[
196
+ Optional[str],
197
+ PydanticField(
198
+ default=None,
199
+ description="API key for the agent",
200
+ ),
201
+ ]
202
+ api_key_public: Annotated[
203
+ Optional[str],
204
+ PydanticField(
205
+ default=None,
206
+ description="Public API key for the agent",
207
+ ),
208
+ ]
209
+ created_at: Annotated[
210
+ datetime,
211
+ PydanticField(
212
+ default_factory=lambda: datetime.now(timezone.utc),
213
+ description="Timestamp when the agent data was created",
214
+ ),
215
+ ]
216
+ updated_at: Annotated[
217
+ datetime,
218
+ PydanticField(
219
+ default_factory=lambda: datetime.now(timezone.utc),
220
+ description="Timestamp when the agent data was last updated",
221
+ ),
222
+ ]
223
+
224
+ @classmethod
225
+ async def get(cls, agent_id: str) -> Optional["AgentData"]:
226
+ """Get agent data by ID.
227
+
228
+ Args:
229
+ agent_id: Agent ID
230
+
231
+ Returns:
232
+ AgentData if found, None otherwise
233
+
234
+ Raises:
235
+ HTTPException: If there are database errors
236
+ """
237
+ async with get_session() as db:
238
+ item = await db.get(AgentDataTable, agent_id)
239
+ if item:
240
+ return cls.model_validate(item)
241
+ return cls.model_construct(id=agent_id)
242
+
243
+ @classmethod
244
+ async def get_by_api_key(cls, api_key: str) -> Optional["AgentData"]:
245
+ """Get agent data by API key.
246
+
247
+ Args:
248
+ api_key: API key (sk- for private, pk- for public)
249
+
250
+ Returns:
251
+ AgentData if found, None otherwise
252
+
253
+ Raises:
254
+ HTTPException: If there are database errors
255
+ """
256
+ async with get_session() as db:
257
+ if api_key.startswith("sk-"):
258
+ # Search in api_key field for private keys
259
+ result = await db.execute(
260
+ select(AgentDataTable).where(AgentDataTable.api_key == api_key)
261
+ )
262
+ elif api_key.startswith("pk-"):
263
+ # Search in api_key_public field for public keys
264
+ result = await db.execute(
265
+ select(AgentDataTable).where(
266
+ AgentDataTable.api_key_public == api_key
267
+ )
268
+ )
269
+ else:
270
+ # Invalid key format
271
+ return None
272
+
273
+ item = result.scalar_one_or_none()
274
+ if item:
275
+ return cls.model_validate(item)
276
+ return None
277
+
278
+ async def save(self) -> None:
279
+ """Save or update agent data.
280
+
281
+ Raises:
282
+ HTTPException: If there are database errors
283
+ """
284
+ async with get_session() as db:
285
+ existing = await db.get(AgentDataTable, self.id)
286
+ if existing:
287
+ # Update existing record
288
+ for field, value in self.model_dump(exclude_unset=True).items():
289
+ setattr(existing, field, value)
290
+ db.add(existing)
291
+ else:
292
+ # Create new record
293
+ db_agent_data = AgentDataTable(**self.model_dump())
294
+ db.add(db_agent_data)
295
+
296
+ await db.commit()
297
+
298
+ @staticmethod
299
+ async def patch(id: str, data: dict) -> "AgentData":
300
+ """Update agent data.
301
+
302
+ Args:
303
+ id: ID of the agent
304
+ data: Dictionary containing fields to update
305
+
306
+ Returns:
307
+ Updated agent data
308
+
309
+ Raises:
310
+ HTTPException: If there are database errors
311
+ """
312
+ async with get_session() as db:
313
+ agent_data = await db.get(AgentDataTable, id)
314
+ if not agent_data:
315
+ agent_data = AgentDataTable(id=id, **data)
316
+ db.add(agent_data)
317
+ else:
318
+ for key, value in data.items():
319
+ setattr(agent_data, key, value)
320
+ await db.commit()
321
+ await db.refresh(agent_data)
322
+ return AgentData.model_validate(agent_data)
323
+
324
+
325
+ class AgentPluginDataTable(Base):
326
+ """Database model for storing plugin-specific data for agents.
327
+
328
+ This model uses a composite primary key of (agent_id, plugin, key) to store
329
+ plugin-specific data for agents in a flexible way.
330
+
331
+ Attributes:
332
+ agent_id: ID of the agent this data belongs to
333
+ plugin: Name of the plugin this data is for
334
+ key: Key for this specific piece of data
335
+ data: JSON data stored for this key
336
+ """
337
+
338
+ __tablename__ = "agent_plugin_data"
339
+
340
+ agent_id = Column(String, primary_key=True)
341
+ plugin = Column(String, primary_key=True)
342
+ key = Column(String, primary_key=True)
343
+ data = Column(JSON().with_variant(JSONB(), "postgresql"), nullable=True)
344
+ created_at = Column(
345
+ DateTime(timezone=True),
346
+ nullable=False,
347
+ server_default=func.now(),
348
+ )
349
+ updated_at = Column(
350
+ DateTime(timezone=True),
351
+ nullable=False,
352
+ server_default=func.now(),
353
+ onupdate=lambda: datetime.now(timezone.utc),
354
+ )
355
+
356
+
357
+ class AgentPluginData(BaseModel):
358
+ """Model for storing plugin-specific data for agents.
359
+
360
+ This model uses a composite primary key of (agent_id, plugin, key) to store
361
+ plugin-specific data for agents in a flexible way.
362
+
363
+ Attributes:
364
+ agent_id: ID of the agent this data belongs to
365
+ plugin: Name of the plugin this data is for
366
+ key: Key for this specific piece of data
367
+ data: JSON data stored for this key
368
+ """
369
+
370
+ model_config = ConfigDict(from_attributes=True)
371
+
372
+ agent_id: Annotated[
373
+ str,
374
+ PydanticField(description="ID of the agent this data belongs to"),
375
+ ]
376
+ plugin: Annotated[
377
+ str,
378
+ PydanticField(description="Name of the plugin this data is for"),
379
+ ]
380
+ key: Annotated[
381
+ str,
382
+ PydanticField(description="Key for this specific piece of data"),
383
+ ]
384
+ data: Annotated[
385
+ Dict[str, Any],
386
+ PydanticField(default=None, description="JSON data stored for this key"),
387
+ ]
388
+ created_at: Annotated[
389
+ datetime,
390
+ PydanticField(
391
+ description="Timestamp when this data was created",
392
+ default_factory=lambda: datetime.now(timezone.utc),
393
+ ),
394
+ ]
395
+ updated_at: Annotated[
396
+ datetime,
397
+ PydanticField(
398
+ description="Timestamp when this data was last updated",
399
+ default_factory=lambda: datetime.now(timezone.utc),
400
+ ),
401
+ ]
402
+
403
+ @classmethod
404
+ async def get(
405
+ cls, agent_id: str, plugin: str, key: str
406
+ ) -> Optional["AgentPluginData"]:
407
+ """Get plugin data for an agent.
408
+
409
+ Args:
410
+ agent_id: ID of the agent
411
+ plugin: Name of the plugin
412
+ key: Data key
413
+
414
+ Returns:
415
+ AgentPluginData if found, None otherwise
416
+
417
+ Raises:
418
+ HTTPException: If there are database errors
419
+ """
420
+ async with get_session() as db:
421
+ item = await db.scalar(
422
+ select(AgentPluginDataTable).where(
423
+ AgentPluginDataTable.agent_id == agent_id,
424
+ AgentPluginDataTable.plugin == plugin,
425
+ AgentPluginDataTable.key == key,
426
+ )
427
+ )
428
+ if item:
429
+ return cls.model_validate(item)
430
+ return None
431
+
432
+ async def save(self) -> None:
433
+ """Save or update plugin data.
434
+
435
+ Raises:
436
+ HTTPException: If there are database errors
437
+ """
438
+ async with get_session() as db:
439
+ plugin_data = await db.scalar(
440
+ select(AgentPluginDataTable).where(
441
+ AgentPluginDataTable.agent_id == self.agent_id,
442
+ AgentPluginDataTable.plugin == self.plugin,
443
+ AgentPluginDataTable.key == self.key,
444
+ )
445
+ )
446
+
447
+ if plugin_data:
448
+ # Update existing record
449
+ plugin_data.data = self.data
450
+ db.add(plugin_data)
451
+ else:
452
+ # Create new record
453
+ plugin_data = AgentPluginDataTable(
454
+ agent_id=self.agent_id,
455
+ plugin=self.plugin,
456
+ key=self.key,
457
+ data=self.data,
458
+ )
459
+ db.add(plugin_data)
460
+
461
+ await db.commit()
462
+ await db.refresh(plugin_data)
463
+
464
+ # Refresh the model with updated data
465
+ self.model_validate(plugin_data)
466
+
467
+
468
+ class AgentQuotaTable(Base):
469
+ """AgentQuota database table model."""
470
+
471
+ __tablename__ = "agent_quotas"
472
+
473
+ id = Column(String, primary_key=True)
474
+ plan = Column(String, default="self-hosted")
475
+ message_count_total = Column(BigInteger, default=0)
476
+ message_limit_total = Column(BigInteger, default=99999999)
477
+ message_count_monthly = Column(BigInteger, default=0)
478
+ message_limit_monthly = Column(BigInteger, default=99999999)
479
+ message_count_daily = Column(BigInteger, default=0)
480
+ message_limit_daily = Column(BigInteger, default=99999999)
481
+ last_message_time = Column(DateTime(timezone=True), default=None, nullable=True)
482
+ autonomous_count_total = Column(BigInteger, default=0)
483
+ autonomous_limit_total = Column(BigInteger, default=99999999)
484
+ autonomous_count_monthly = Column(BigInteger, default=0)
485
+ autonomous_limit_monthly = Column(BigInteger, default=99999999)
486
+ last_autonomous_time = Column(DateTime(timezone=True), default=None, nullable=True)
487
+ twitter_count_total = Column(BigInteger, default=0)
488
+ twitter_limit_total = Column(BigInteger, default=99999999)
489
+ twitter_count_monthly = Column(BigInteger, default=0)
490
+ twitter_limit_monthly = Column(BigInteger, default=99999999)
491
+ twitter_count_daily = Column(BigInteger, default=0)
492
+ twitter_limit_daily = Column(BigInteger, default=99999999)
493
+ last_twitter_time = Column(DateTime(timezone=True), default=None, nullable=True)
494
+ free_income_daily = Column(Numeric(22, 4), default=0)
495
+ avg_action_cost = Column(Numeric(22, 4), default=0)
496
+ min_action_cost = Column(Numeric(22, 4), default=0)
497
+ max_action_cost = Column(Numeric(22, 4), default=0)
498
+ low_action_cost = Column(Numeric(22, 4), default=0)
499
+ medium_action_cost = Column(Numeric(22, 4), default=0)
500
+ high_action_cost = Column(Numeric(22, 4), default=0)
501
+ created_at = Column(
502
+ DateTime(timezone=True),
503
+ nullable=False,
504
+ server_default=func.now(),
505
+ )
506
+ updated_at = Column(
507
+ DateTime(timezone=True),
508
+ nullable=False,
509
+ server_default=func.now(),
510
+ onupdate=lambda: datetime.now(timezone.utc),
511
+ )
512
+
513
+
514
+ class AgentQuota(BaseModel):
515
+ """AgentQuota model."""
516
+
517
+ model_config = ConfigDict(from_attributes=True)
518
+
519
+ id: Annotated[
520
+ str, PydanticField(description="ID of the agent this quota belongs to")
521
+ ]
522
+ plan: Annotated[
523
+ str, PydanticField(default="self-hosted", description="Agent plan name")
524
+ ]
525
+ message_count_total: Annotated[
526
+ int, PydanticField(default=0, description="Total message count")
527
+ ]
528
+ message_limit_total: Annotated[
529
+ int, PydanticField(default=99999999, description="Total message limit")
530
+ ]
531
+ message_count_monthly: Annotated[
532
+ int, PydanticField(default=0, description="Monthly message count")
533
+ ]
534
+ message_limit_monthly: Annotated[
535
+ int, PydanticField(default=99999999, description="Monthly message limit")
536
+ ]
537
+ message_count_daily: Annotated[
538
+ int, PydanticField(default=0, description="Daily message count")
539
+ ]
540
+ message_limit_daily: Annotated[
541
+ int, PydanticField(default=99999999, description="Daily message limit")
542
+ ]
543
+ last_message_time: Annotated[
544
+ Optional[datetime],
545
+ PydanticField(default=None, description="Last message timestamp"),
546
+ ]
547
+ autonomous_count_total: Annotated[
548
+ int, PydanticField(default=0, description="Total autonomous operations count")
549
+ ]
550
+ autonomous_limit_total: Annotated[
551
+ int,
552
+ PydanticField(
553
+ default=99999999, description="Total autonomous operations limit"
554
+ ),
555
+ ]
556
+ autonomous_count_monthly: Annotated[
557
+ int, PydanticField(default=0, description="Monthly autonomous operations count")
558
+ ]
559
+ autonomous_limit_monthly: Annotated[
560
+ int,
561
+ PydanticField(
562
+ default=99999999, description="Monthly autonomous operations limit"
563
+ ),
564
+ ]
565
+ autonomous_count_daily: Annotated[
566
+ int, PydanticField(default=0, description="Daily autonomous operations count")
567
+ ]
568
+ autonomous_limit_daily: Annotated[
569
+ int,
570
+ PydanticField(
571
+ default=99999999, description="Daily autonomous operations limit"
572
+ ),
573
+ ]
574
+ last_autonomous_time: Annotated[
575
+ Optional[datetime],
576
+ PydanticField(default=None, description="Last autonomous operation timestamp"),
577
+ ]
578
+ twitter_count_total: Annotated[
579
+ int, PydanticField(default=0, description="Total Twitter operations count")
580
+ ]
581
+ twitter_limit_total: Annotated[
582
+ int,
583
+ PydanticField(default=99999999, description="Total Twitter operations limit"),
584
+ ]
585
+ twitter_count_monthly: Annotated[
586
+ int, PydanticField(default=0, description="Monthly Twitter operations count")
587
+ ]
588
+ twitter_limit_monthly: Annotated[
589
+ int,
590
+ PydanticField(default=99999999, description="Monthly Twitter operations limit"),
591
+ ]
592
+ twitter_count_daily: Annotated[
593
+ int, PydanticField(default=0, description="Daily Twitter operations count")
594
+ ]
595
+ twitter_limit_daily: Annotated[
596
+ int,
597
+ PydanticField(default=99999999, description="Daily Twitter operations limit"),
598
+ ]
599
+ last_twitter_time: Annotated[
600
+ Optional[datetime],
601
+ PydanticField(default=None, description="Last Twitter operation timestamp"),
602
+ ]
603
+ free_income_daily: Annotated[
604
+ Decimal,
605
+ PydanticField(default=0, description="Daily free income amount"),
606
+ ]
607
+ avg_action_cost: Annotated[
608
+ Decimal,
609
+ PydanticField(default=0, description="Average cost per action"),
610
+ ]
611
+ max_action_cost: Annotated[
612
+ Decimal,
613
+ PydanticField(default=0, description="Maximum cost per action"),
614
+ ]
615
+ min_action_cost: Annotated[
616
+ Decimal,
617
+ PydanticField(default=0, description="Minimum cost per action"),
618
+ ]
619
+ high_action_cost: Annotated[
620
+ Decimal,
621
+ PydanticField(default=0, description="High expected action cost"),
622
+ ]
623
+ medium_action_cost: Annotated[
624
+ Decimal,
625
+ PydanticField(default=0, description="Medium expected action cost"),
626
+ ]
627
+ low_action_cost: Annotated[
628
+ Decimal,
629
+ PydanticField(default=0, description="Low expected action cost"),
630
+ ]
631
+ created_at: Annotated[
632
+ datetime,
633
+ PydanticField(
634
+ description="Timestamp when this quota was created",
635
+ default_factory=lambda: datetime.now(timezone.utc),
636
+ ),
637
+ ]
638
+ updated_at: Annotated[
639
+ datetime,
640
+ PydanticField(
641
+ description="Timestamp when this quota was last updated",
642
+ default_factory=lambda: datetime.now(timezone.utc),
643
+ ),
644
+ ]
645
+
646
+ @classmethod
647
+ async def get(cls, agent_id: str) -> "AgentQuota":
648
+ """Get agent quota by id, if not exists, create a new one.
649
+
650
+ Args:
651
+ agent_id: Agent ID
652
+
653
+ Returns:
654
+ AgentQuota: The agent's quota object
655
+
656
+ Raises:
657
+ HTTPException: If there are database errors
658
+ """
659
+ async with get_session() as db:
660
+ quota_record = await db.get(AgentQuotaTable, agent_id)
661
+ if not quota_record:
662
+ # Create new record
663
+ quota_record = AgentQuotaTable(
664
+ id=agent_id,
665
+ )
666
+ db.add(quota_record)
667
+ await db.commit()
668
+ await db.refresh(quota_record)
669
+
670
+ return cls.model_validate(quota_record)
671
+
672
+ def has_message_quota(self) -> bool:
673
+ """Check if the agent has message quota.
674
+
675
+ Returns:
676
+ bool: True if the agent has quota, False otherwise
677
+ """
678
+ # Check total limit
679
+ if self.message_count_total >= self.message_limit_total:
680
+ return False
681
+ # Check monthly limit
682
+ if self.message_count_monthly >= self.message_limit_monthly:
683
+ return False
684
+ # Check daily limit
685
+ if self.message_count_daily >= self.message_limit_daily:
686
+ return False
687
+ return True
688
+
689
+ def has_autonomous_quota(self) -> bool:
690
+ """Check if the agent has autonomous quota.
691
+
692
+ Returns:
693
+ bool: True if the agent has quota, False otherwise
694
+ """
695
+ # Check total limit
696
+ if self.autonomous_count_total >= self.autonomous_limit_total:
697
+ return False
698
+ # Check monthly limit
699
+ if self.autonomous_count_monthly >= self.autonomous_limit_monthly:
700
+ return False
701
+ return True
702
+
703
+ def has_twitter_quota(self) -> bool:
704
+ """Check if the agent has twitter quota.
705
+
706
+ Returns:
707
+ bool: True if the agent has quota, False otherwise
708
+ """
709
+ # Check total limit
710
+ if self.twitter_count_total >= self.twitter_limit_total:
711
+ return False
712
+ # Check daily limit
713
+ if self.twitter_count_daily >= self.twitter_limit_daily:
714
+ return False
715
+ return True
716
+
717
+ @staticmethod
718
+ async def add_free_income_in_session(session, id: str, amount: Decimal) -> None:
719
+ """Add free income to an agent's quota directly in the database.
720
+
721
+ Args:
722
+ session: SQLAlchemy session
723
+ id: Agent ID
724
+ amount: Amount to add to free_income_daily
725
+
726
+ Raises:
727
+ HTTPException: If there are database errors
728
+ """
729
+ try:
730
+ # Check if the record exists using session.get
731
+ quota_record = await session.get(AgentQuotaTable, id)
732
+
733
+ if not quota_record:
734
+ # Create new record if it doesn't exist
735
+ quota_record = AgentQuotaTable(id=id, free_income_daily=amount)
736
+ session.add(quota_record)
737
+ else:
738
+ # Use update statement with func to directly add the amount
739
+ from sqlalchemy import update
740
+
741
+ stmt = update(AgentQuotaTable).where(AgentQuotaTable.id == id)
742
+ stmt = stmt.values(
743
+ free_income_daily=func.coalesce(
744
+ AgentQuotaTable.free_income_daily, 0
745
+ )
746
+ + amount
747
+ )
748
+ await session.execute(stmt)
749
+ except Exception as e:
750
+ logger.error(f"Error adding free income: {str(e)}")
751
+ raise HTTPException(status_code=500, detail=f"Database error: {str(e)}")
752
+
753
+ async def add_message(self) -> None:
754
+ """Add a message to the agent's message count."""
755
+ async with get_session() as db:
756
+ quota_record = await db.get(AgentQuotaTable, self.id)
757
+
758
+ if quota_record:
759
+ # Update record
760
+ quota_record.message_count_total += 1
761
+ quota_record.message_count_monthly += 1
762
+ quota_record.message_count_daily += 1
763
+ quota_record.last_message_time = datetime.now(timezone.utc)
764
+ db.add(quota_record)
765
+ await db.commit()
766
+
767
+ # Update this instance
768
+ await db.refresh(quota_record)
769
+ self.message_count_total = quota_record.message_count_total
770
+ self.message_count_monthly = quota_record.message_count_monthly
771
+ self.message_count_daily = quota_record.message_count_daily
772
+ self.last_message_time = quota_record.last_message_time
773
+ self.updated_at = quota_record.updated_at
774
+
775
+ async def add_autonomous(self) -> None:
776
+ """Add an autonomous operation to the agent's autonomous count."""
777
+ async with get_session() as db:
778
+ quota_record = await db.get(AgentQuotaTable, self.id)
779
+ if quota_record:
780
+ # Update record
781
+ quota_record.autonomous_count_total += 1
782
+ quota_record.autonomous_count_monthly += 1
783
+ quota_record.last_autonomous_time = datetime.now(timezone.utc)
784
+ db.add(quota_record)
785
+ await db.commit()
786
+
787
+ # Update this instance
788
+ await db.refresh(quota_record)
789
+ self.model_validate(quota_record)
790
+
791
+ async def add_twitter_message(self) -> None:
792
+ """Add a twitter message to the agent's twitter count.
793
+
794
+ Raises:
795
+ HTTPException: If there are database errors
796
+ """
797
+ async with get_session() as db:
798
+ quota_record = await db.get(AgentQuotaTable, self.id)
799
+
800
+ if quota_record:
801
+ # Update record
802
+ quota_record.twitter_count_total += 1
803
+ quota_record.twitter_count_daily += 1
804
+ quota_record.last_twitter_time = datetime.now(timezone.utc)
805
+ db.add(quota_record)
806
+ await db.commit()
807
+
808
+ # Update this instance
809
+ await db.refresh(quota_record)
810
+ self.model_validate(quota_record)