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,132 @@
1
+ """Redis client module for IntentKit."""
2
+
3
+ import logging
4
+ from typing import Optional
5
+
6
+ from redis.asyncio import Redis
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ # Global Redis client instance
11
+ _redis_client: Optional[Redis] = None
12
+
13
+
14
+ async def init_redis(
15
+ host: str,
16
+ port: int = 6379,
17
+ db: int = 0,
18
+ password: Optional[str] = None,
19
+ ssl: bool = False,
20
+ encoding: str = "utf-8",
21
+ decode_responses: bool = True,
22
+ ) -> Redis:
23
+ """Initialize the Redis client.
24
+
25
+ Args:
26
+ host: Redis host
27
+ port: Redis port (default: 6379)
28
+ db: Redis database number (default: 0)
29
+ password: Redis password (default: None)
30
+ ssl: Whether to use SSL (default: False)
31
+ encoding: Response encoding (default: utf-8)
32
+ decode_responses: Whether to decode responses (default: True)
33
+
34
+ Returns:
35
+ Redis: The initialized Redis client
36
+ """
37
+ global _redis_client
38
+
39
+ if _redis_client is not None:
40
+ logger.info("Redis client already initialized")
41
+ return _redis_client
42
+
43
+ try:
44
+ logger.info(f"Initializing Redis client at {host}:{port}")
45
+ _redis_client = Redis(
46
+ host=host,
47
+ port=port,
48
+ db=db,
49
+ password=password,
50
+ ssl=ssl,
51
+ encoding=encoding,
52
+ decode_responses=decode_responses,
53
+ )
54
+ # Test the connection
55
+ await _redis_client.ping()
56
+ logger.info("Redis client initialized successfully")
57
+ return _redis_client
58
+ except Exception as e:
59
+ logger.error(f"Failed to initialize Redis client: {e}")
60
+ raise
61
+
62
+
63
+ def get_redis() -> Redis:
64
+ """Get the Redis client.
65
+
66
+ Returns:
67
+ Redis: The Redis client
68
+
69
+ Raises:
70
+ RuntimeError: If the Redis client is not initialized
71
+ """
72
+ if _redis_client is None:
73
+ raise RuntimeError("Redis client not initialized. Call init_redis first.")
74
+ return _redis_client
75
+
76
+
77
+ async def send_heartbeat(redis_client: Redis, name: str) -> None:
78
+ """Set a heartbeat key in Redis that expires after 16 minutes.
79
+
80
+ Args:
81
+ redis_client: Redis client instance
82
+ name: Name identifier for the heartbeat
83
+ """
84
+ try:
85
+ key = f"intentkit:heartbeat:{name}"
86
+ await redis_client.set(key, 1, ex=190) # 190 seconds = 3 minutes
87
+ except Exception as e:
88
+ logger.error(f"Failed to send heartbeat for {name}: {e}")
89
+
90
+
91
+ async def check_heartbeat(redis_client: Redis, name: str) -> bool:
92
+ """Check if a heartbeat key exists in Redis.
93
+
94
+ Args:
95
+ redis_client: Redis client instance
96
+ name: Name identifier for the heartbeat
97
+
98
+ Returns:
99
+ bool: True if heartbeat exists, False otherwise
100
+ """
101
+ import asyncio
102
+
103
+ key = f"intentkit:heartbeat:{name}"
104
+ retries = 3
105
+
106
+ for attempt in range(retries):
107
+ try:
108
+ exists = await redis_client.exists(key)
109
+ return bool(exists)
110
+ except Exception as e:
111
+ logger.error(
112
+ f"Error checking heartbeat for {name} (attempt {attempt + 1}/{retries}): {e}"
113
+ )
114
+ if attempt < retries - 1: # Don't sleep on the last attempt
115
+ await asyncio.sleep(5) # Wait 5 seconds before retrying
116
+
117
+ return False
118
+
119
+
120
+ async def clean_heartbeat(redis_client: Redis, name: str) -> None:
121
+ """Remove a heartbeat key from Redis.
122
+
123
+ Args:
124
+ redis_client: Redis client instance
125
+ name: Name identifier for the heartbeat to remove
126
+ """
127
+ try:
128
+ key = f"intentkit:heartbeat:{name}"
129
+ await redis_client.delete(key)
130
+ logger.info(f"Removed heartbeat for {name}")
131
+ except Exception as e:
132
+ logger.error(f"Failed to remove heartbeat for {name}: {e}")
@@ -0,0 +1,466 @@
1
+ import json
2
+ from datetime import datetime, timezone
3
+ from decimal import Decimal
4
+ from typing import Annotated, Any, Dict, Optional
5
+
6
+ from intentkit.models.base import Base
7
+ from intentkit.models.db import get_session
8
+ from intentkit.models.redis import get_redis
9
+ from pydantic import BaseModel, ConfigDict, Field
10
+ from sqlalchemy import (
11
+ Boolean,
12
+ Column,
13
+ DateTime,
14
+ Integer,
15
+ Numeric,
16
+ String,
17
+ delete,
18
+ func,
19
+ select,
20
+ )
21
+ from sqlalchemy.dialects.postgresql import JSON, JSONB
22
+
23
+
24
+ class AgentSkillDataTable(Base):
25
+ """Database table model for storing skill-specific data for agents."""
26
+
27
+ __tablename__ = "agent_skill_data"
28
+
29
+ agent_id = Column(String, primary_key=True)
30
+ skill = Column(String, primary_key=True)
31
+ key = Column(String, primary_key=True)
32
+ data = Column(JSON().with_variant(JSONB(), "postgresql"), nullable=True)
33
+ size = Column(Integer, nullable=False, default=0)
34
+ created_at = Column(
35
+ DateTime(timezone=True),
36
+ nullable=False,
37
+ server_default=func.now(),
38
+ )
39
+ updated_at = Column(
40
+ DateTime(timezone=True),
41
+ nullable=False,
42
+ server_default=func.now(),
43
+ onupdate=lambda: datetime.now(timezone.utc),
44
+ )
45
+
46
+
47
+ class AgentSkillDataCreate(BaseModel):
48
+ """Base model for creating agent skill data records."""
49
+
50
+ model_config = ConfigDict(from_attributes=True)
51
+
52
+ agent_id: Annotated[str, Field(description="ID of the agent this data belongs to")]
53
+ skill: Annotated[str, Field(description="Name of the skill this data is for")]
54
+ key: Annotated[str, Field(description="Key for this specific piece of data")]
55
+ data: Annotated[Dict[str, Any], Field(description="JSON data stored for this key")]
56
+
57
+ async def save(self) -> "AgentSkillData":
58
+ """Save or update skill data.
59
+
60
+ Returns:
61
+ AgentSkillData: The saved agent skill data instance
62
+
63
+ Raises:
64
+ Exception: If the total size would exceed the 10MB limit
65
+ """
66
+ # Calculate the size of the data
67
+ data_size = len(json.dumps(self.data).encode("utf-8"))
68
+
69
+ async with get_session() as db:
70
+ # Check current total size for this agent
71
+ current_total = await AgentSkillData.total_size(self.agent_id)
72
+
73
+ record = await db.scalar(
74
+ select(AgentSkillDataTable).where(
75
+ AgentSkillDataTable.agent_id == self.agent_id,
76
+ AgentSkillDataTable.skill == self.skill,
77
+ AgentSkillDataTable.key == self.key,
78
+ )
79
+ )
80
+
81
+ # Calculate new total size
82
+ if record:
83
+ # Update existing record - subtract old size, add new size
84
+ new_total = current_total - record.size + data_size
85
+ else:
86
+ # Create new record - add new size
87
+ new_total = current_total + data_size
88
+
89
+ # Check if new total would exceed limit (10MB = 10 * 1024 * 1024 bytes)
90
+ if new_total > 10 * 1024 * 1024:
91
+ raise Exception(
92
+ f"Total size would exceed 10MB limit. Current: {current_total}, New: {new_total}"
93
+ )
94
+
95
+ if record:
96
+ # Update existing record
97
+ record.data = self.data
98
+ record.size = data_size
99
+ else:
100
+ # Create new record
101
+ record = AgentSkillDataTable(
102
+ agent_id=self.agent_id,
103
+ skill=self.skill,
104
+ key=self.key,
105
+ data=self.data,
106
+ size=data_size,
107
+ )
108
+
109
+ db.add(record)
110
+ await db.commit()
111
+ await db.refresh(record)
112
+ return AgentSkillData.model_validate(record)
113
+
114
+
115
+ class AgentSkillData(AgentSkillDataCreate):
116
+ """Model for storing skill-specific data for agents.
117
+
118
+ This model uses a composite primary key of (agent_id, skill, key) to store
119
+ skill-specific data for agents in a flexible way.
120
+ """
121
+
122
+ model_config = ConfigDict(
123
+ from_attributes=True,
124
+ json_encoders={datetime: lambda v: v.isoformat(timespec="milliseconds")},
125
+ )
126
+
127
+ size: Annotated[int, Field(description="Size of the data in bytes")]
128
+ created_at: Annotated[
129
+ datetime, Field(description="Timestamp when this data was created")
130
+ ]
131
+ updated_at: Annotated[
132
+ datetime, Field(description="Timestamp when this data was updated")
133
+ ]
134
+
135
+ @classmethod
136
+ async def total_size(cls, agent_id: str) -> int:
137
+ """Calculate the total size of all skill data for an agent.
138
+
139
+ Args:
140
+ agent_id: ID of the agent
141
+
142
+ Returns:
143
+ int: Total size in bytes of all skill data for the agent
144
+ """
145
+ async with get_session() as db:
146
+ result = await db.scalar(
147
+ select(func.coalesce(func.sum(AgentSkillDataTable.size), 0)).where(
148
+ AgentSkillDataTable.agent_id == agent_id
149
+ )
150
+ )
151
+ return result or 0
152
+
153
+ @classmethod
154
+ async def get(cls, agent_id: str, skill: str, key: str) -> Optional[dict]:
155
+ """Get skill data for an agent.
156
+
157
+ Args:
158
+ agent_id: ID of the agent
159
+ skill: Name of the skill
160
+ key: Data key
161
+
162
+ Returns:
163
+ Dictionary containing the skill data if found, None otherwise
164
+ """
165
+ async with get_session() as db:
166
+ result = await db.scalar(
167
+ select(AgentSkillDataTable).where(
168
+ AgentSkillDataTable.agent_id == agent_id,
169
+ AgentSkillDataTable.skill == skill,
170
+ AgentSkillDataTable.key == key,
171
+ )
172
+ )
173
+ return result.data if result else None
174
+
175
+ @classmethod
176
+ async def clean_data(cls, agent_id: str):
177
+ """Clean all skill data for an agent.
178
+
179
+ Args:
180
+ agent_id: ID of the agent
181
+ """
182
+ async with get_session() as db:
183
+ await db.execute(
184
+ delete(AgentSkillDataTable).where(
185
+ AgentSkillDataTable.agent_id == agent_id
186
+ )
187
+ )
188
+ await db.commit()
189
+
190
+
191
+ class ThreadSkillDataTable(Base):
192
+ """Database table model for storing skill-specific data for threads."""
193
+
194
+ __tablename__ = "thread_skill_data"
195
+
196
+ thread_id = Column(String, primary_key=True)
197
+ skill = Column(String, primary_key=True)
198
+ key = Column(String, primary_key=True)
199
+ agent_id = Column(String, nullable=False)
200
+ data = Column(JSON().with_variant(JSONB(), "postgresql"), nullable=True)
201
+ created_at = Column(
202
+ DateTime(timezone=True),
203
+ nullable=False,
204
+ server_default=func.now(),
205
+ )
206
+ updated_at = Column(
207
+ DateTime(timezone=True),
208
+ nullable=False,
209
+ server_default=func.now(),
210
+ onupdate=lambda: datetime.now(timezone.utc),
211
+ )
212
+
213
+
214
+ class ThreadSkillDataCreate(BaseModel):
215
+ """Base model for creating thread skill data records."""
216
+
217
+ model_config = ConfigDict(from_attributes=True)
218
+
219
+ thread_id: Annotated[
220
+ str, Field(description="ID of the thread this data belongs to")
221
+ ]
222
+ skill: Annotated[str, Field(description="Name of the skill this data is for")]
223
+ key: Annotated[str, Field(description="Key for this specific piece of data")]
224
+ agent_id: Annotated[str, Field(description="ID of the agent that owns this thread")]
225
+ data: Annotated[Dict[str, Any], Field(description="JSON data stored for this key")]
226
+
227
+ async def save(self) -> "ThreadSkillData":
228
+ """Save or update skill data.
229
+
230
+ Returns:
231
+ ThreadSkillData: The saved thread skill data instance
232
+ """
233
+ async with get_session() as db:
234
+ record = await db.scalar(
235
+ select(ThreadSkillDataTable).where(
236
+ ThreadSkillDataTable.thread_id == self.thread_id,
237
+ ThreadSkillDataTable.skill == self.skill,
238
+ ThreadSkillDataTable.key == self.key,
239
+ )
240
+ )
241
+
242
+ if record:
243
+ # Update existing record
244
+ record.data = self.data
245
+ record.agent_id = self.agent_id
246
+ else:
247
+ # Create new record
248
+ record = ThreadSkillDataTable(**self.model_dump())
249
+ db.add(record)
250
+ await db.commit()
251
+ await db.refresh(record)
252
+ return ThreadSkillData.model_validate(record)
253
+
254
+
255
+ class ThreadSkillData(ThreadSkillDataCreate):
256
+ """Model for storing skill-specific data for threads.
257
+
258
+ This model uses a composite primary key of (thread_id, skill, key) to store
259
+ skill-specific data for threads in a flexible way. It also includes agent_id
260
+ as a required field for tracking ownership.
261
+ """
262
+
263
+ model_config = ConfigDict(
264
+ from_attributes=True,
265
+ json_encoders={datetime: lambda v: v.isoformat(timespec="milliseconds")},
266
+ )
267
+
268
+ created_at: Annotated[
269
+ datetime, Field(description="Timestamp when this data was created")
270
+ ]
271
+ updated_at: Annotated[
272
+ datetime, Field(description="Timestamp when this data was updated")
273
+ ]
274
+
275
+ @classmethod
276
+ async def get(cls, thread_id: str, skill: str, key: str) -> Optional[dict]:
277
+ """Get skill data for a thread.
278
+
279
+ Args:
280
+ thread_id: ID of the thread
281
+ skill: Name of the skill
282
+ key: Data key
283
+
284
+ Returns:
285
+ Dictionary containing the skill data if found, None otherwise
286
+ """
287
+ async with get_session() as db:
288
+ record = await db.scalar(
289
+ select(ThreadSkillDataTable).where(
290
+ ThreadSkillDataTable.thread_id == thread_id,
291
+ ThreadSkillDataTable.skill == skill,
292
+ ThreadSkillDataTable.key == key,
293
+ )
294
+ )
295
+ return record.data if record else None
296
+
297
+ @classmethod
298
+ async def clean_data(
299
+ cls,
300
+ agent_id: str,
301
+ thread_id: Annotated[
302
+ str,
303
+ Field(
304
+ default="",
305
+ description="Optional ID of the thread. If provided, only cleans data for that thread.",
306
+ ),
307
+ ],
308
+ ):
309
+ """Clean all skill data for a thread or agent.
310
+
311
+ Args:
312
+ agent_id: ID of the agent
313
+ thread_id: Optional ID of the thread. If provided, only cleans data for that thread.
314
+ If empty, cleans all data for the agent.
315
+ """
316
+ async with get_session() as db:
317
+ if thread_id and thread_id != "":
318
+ await db.execute(
319
+ delete(ThreadSkillDataTable).where(
320
+ ThreadSkillDataTable.agent_id == agent_id,
321
+ ThreadSkillDataTable.thread_id == thread_id,
322
+ )
323
+ )
324
+ else:
325
+ await db.execute(
326
+ delete(ThreadSkillDataTable).where(
327
+ ThreadSkillDataTable.agent_id == agent_id
328
+ )
329
+ )
330
+ await db.commit()
331
+
332
+
333
+ class SkillTable(Base):
334
+ """Database table model for Skill."""
335
+
336
+ __tablename__ = "skills"
337
+
338
+ name = Column(String, primary_key=True)
339
+ enabled = Column(Boolean, nullable=False, default=True)
340
+ category = Column(String, nullable=False)
341
+ config_name = Column(String, nullable=True)
342
+ price_level = Column(Integer, nullable=True)
343
+ price = Column(Numeric(22, 4), nullable=False, default=1)
344
+ price_self_key = Column(Numeric(22, 4), nullable=False, default=1)
345
+ rate_limit_count = Column(Integer, nullable=True)
346
+ rate_limit_minutes = Column(Integer, nullable=True)
347
+ author = Column(String, nullable=True)
348
+ created_at = Column(
349
+ DateTime(timezone=True),
350
+ nullable=False,
351
+ server_default=func.now(),
352
+ )
353
+ updated_at = Column(
354
+ DateTime(timezone=True),
355
+ nullable=False,
356
+ server_default=func.now(),
357
+ onupdate=lambda: datetime.now(timezone.utc),
358
+ )
359
+
360
+
361
+ class Skill(BaseModel):
362
+ """Pydantic model for Skill."""
363
+
364
+ model_config = ConfigDict(
365
+ from_attributes=True,
366
+ json_encoders={
367
+ datetime: lambda v: v.isoformat(timespec="milliseconds"),
368
+ },
369
+ )
370
+
371
+ name: Annotated[str, Field(description="Name of the skill")]
372
+ enabled: Annotated[bool, Field(description="Is this skill enabled?")]
373
+ category: Annotated[str, Field(description="Category of the skill")]
374
+ config_name: Annotated[Optional[str], Field(description="Config name of the skill")]
375
+ price_level: Annotated[
376
+ Optional[int], Field(description="Price level for this skill")
377
+ ]
378
+ price: Annotated[
379
+ Decimal, Field(description="Price for this skill", default=Decimal("1"))
380
+ ]
381
+ price_self_key: Annotated[
382
+ Decimal,
383
+ Field(description="Price for this skill with self key", default=Decimal("1")),
384
+ ]
385
+ rate_limit_count: Annotated[Optional[int], Field(description="Rate limit count")]
386
+ rate_limit_minutes: Annotated[
387
+ Optional[int], Field(description="Rate limit minutes")
388
+ ]
389
+ author: Annotated[Optional[str], Field(description="Author of the skill")]
390
+ created_at: Annotated[
391
+ datetime, Field(description="Timestamp when this record was created")
392
+ ]
393
+ updated_at: Annotated[
394
+ datetime, Field(description="Timestamp when this record was last updated")
395
+ ]
396
+
397
+ @staticmethod
398
+ async def get(name: str) -> Optional["Skill"]:
399
+ """Get a skill by name with Redis caching.
400
+
401
+ The skill is cached in Redis for 3 minutes.
402
+
403
+ Args:
404
+ name: Name of the skill to retrieve
405
+
406
+ Returns:
407
+ Skill: The skill if found, None otherwise
408
+ """
409
+ # Redis cache key for skill
410
+ cache_key = f"intentkit:skill:{name}"
411
+ cache_ttl = 180 # 3 minutes in seconds
412
+
413
+ # Try to get from Redis cache first
414
+ redis = get_redis()
415
+ cached_data = await redis.get(cache_key)
416
+
417
+ if cached_data:
418
+ # If found in cache, deserialize and return
419
+ try:
420
+ return Skill.model_validate_json(cached_data)
421
+ except (json.JSONDecodeError, TypeError):
422
+ # If cache is corrupted, invalidate it
423
+ await redis.delete(cache_key)
424
+
425
+ # If not in cache or cache is invalid, get from database
426
+ async with get_session() as session:
427
+ # Query the database for the skill
428
+ stmt = select(SkillTable).where(SkillTable.name == name)
429
+ skill = await session.scalar(stmt)
430
+
431
+ # If skill doesn't exist, return None
432
+ if not skill:
433
+ return None
434
+
435
+ # Convert to Skill model
436
+ skill_model = Skill.model_validate(skill)
437
+
438
+ # Cache the skill in Redis
439
+ await redis.set(cache_key, skill_model.model_dump_json(), ex=cache_ttl)
440
+
441
+ return skill_model
442
+
443
+ @staticmethod
444
+ async def get_by_config_name(category: str, config_name: str) -> Optional["Skill"]:
445
+ """Get a skill by category and config_name.
446
+
447
+ Args:
448
+ category: Category of the skill
449
+ config_name: Config name of the skill
450
+
451
+ Returns:
452
+ Skill: The skill if found, None otherwise
453
+ """
454
+ async with get_session() as session:
455
+ # Query the database for the skill
456
+ stmt = select(SkillTable).where(
457
+ SkillTable.category == category, SkillTable.config_name == config_name
458
+ )
459
+ skill = await session.scalar(stmt)
460
+
461
+ # If skill doesn't exist, return None
462
+ if not skill:
463
+ return None
464
+
465
+ # Convert to Skill model
466
+ return Skill.model_validate(skill)