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,76 @@
1
+ <svg width="256" height="256" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <!-- Liquid glass gradient -->
4
+ <linearGradient id="glassGradient" x1="0%" y1="0%" x2="100%" y2="100%">
5
+ <stop offset="0%" style="stop-color:#E8F4FD;stop-opacity:0.9"/>
6
+ <stop offset="25%" style="stop-color:#B8E0FF;stop-opacity:0.8"/>
7
+ <stop offset="50%" style="stop-color:#7CC7FF;stop-opacity:0.7"/>
8
+ <stop offset="75%" style="stop-color:#4A9EFF;stop-opacity:0.8"/>
9
+ <stop offset="100%" style="stop-color:#2563EB;stop-opacity:0.9"/>
10
+ </linearGradient>
11
+
12
+ <!-- Inner shadow gradient -->
13
+ <radialGradient id="innerShadow" cx="50%" cy="30%" r="70%">
14
+ <stop offset="0%" style="stop-color:#FFFFFF;stop-opacity:0.6"/>
15
+ <stop offset="70%" style="stop-color:#FFFFFF;stop-opacity:0.2"/>
16
+ <stop offset="100%" style="stop-color:#1E40AF;stop-opacity:0.3"/>
17
+ </radialGradient>
18
+
19
+ <!-- Highlight gradient -->
20
+ <linearGradient id="highlight" x1="0%" y1="0%" x2="100%" y2="50%">
21
+ <stop offset="0%" style="stop-color:#FFFFFF;stop-opacity:0.8"/>
22
+ <stop offset="100%" style="stop-color:#FFFFFF;stop-opacity:0"/>
23
+ </linearGradient>
24
+
25
+ <!-- Drop shadow filter -->
26
+ <filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
27
+ <feDropShadow dx="2" dy="4" stdDeviation="3" flood-color="#000000" flood-opacity="0.2"/>
28
+ </filter>
29
+ </defs>
30
+
31
+ <!-- Background circle -->
32
+ <circle cx="128" cy="128" r="120" fill="#F8FAFC" stroke="#E2E8F0" stroke-width="2" filter="url(#dropShadow)"/>
33
+
34
+ <!-- Main gear shape -->
35
+ <g transform="translate(128,128)">
36
+ <!-- Outer gear teeth -->
37
+ <g fill="url(#glassGradient)" stroke="#1E40AF" stroke-width="1.5" opacity="0.9">
38
+ <!-- 12 gear teeth positioned around the circle -->
39
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(0)"/>
40
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(30)"/>
41
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(60)"/>
42
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(90)"/>
43
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(120)"/>
44
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(150)"/>
45
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(180)"/>
46
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(210)"/>
47
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(240)"/>
48
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(270)"/>
49
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(300)"/>
50
+ <rect x="-8" y="-65" width="16" height="20" rx="2" transform="rotate(330)"/>
51
+ </g>
52
+
53
+ <!-- Main gear body -->
54
+ <circle r="45" fill="url(#glassGradient)" stroke="#1E40AF" stroke-width="2"/>
55
+
56
+ <!-- Inner shadow overlay -->
57
+ <circle r="45" fill="url(#innerShadow)"/>
58
+
59
+ <!-- Center hole -->
60
+ <circle r="18" fill="#FFFFFF" stroke="#CBD5E1" stroke-width="2"/>
61
+
62
+ <!-- Inner hole shadow -->
63
+ <circle r="18" fill="none" stroke="#94A3B8" stroke-width="1" opacity="0.5"/>
64
+
65
+ <!-- Glass highlight effect -->
66
+ <ellipse cx="-15" cy="-15" rx="25" ry="35" fill="url(#highlight)" opacity="0.6" transform="rotate(-30)"/>
67
+
68
+ <!-- Small decorative bolts -->
69
+ <circle cx="0" cy="-30" r="3" fill="#64748B"/>
70
+ <circle cx="26" cy="-15" r="3" fill="#64748B"/>
71
+ <circle cx="26" cy="15" r="3" fill="#64748B"/>
72
+ <circle cx="0" cy="30" r="3" fill="#64748B"/>
73
+ <circle cx="-26" cy="15" r="3" fill="#64748B"/>
74
+ <circle cx="-26" cy="-15" r="3" fill="#64748B"/>
75
+ </g>
76
+ </svg>
@@ -0,0 +1,86 @@
1
+ # Tavily Skills
2
+
3
+ This skill package enables agents to search the web and extract content from web pages using the [Tavily](https://tavily.com/) API.
4
+
5
+ ## Overview
6
+
7
+ The Tavily skills allow agents to:
8
+ - Search the internet for current information
9
+ - Retrieve relevant search results with snippets and URLs
10
+ - Extract full content from specific web pages
11
+ - Find answers to questions that may not be in the agent's training data
12
+ - Access real-time information and news
13
+
14
+ ## Available Skills
15
+
16
+ ### 1. Tavily Search
17
+ Allows agents to search the web for current information and retrieve relevant results.
18
+
19
+ ### 2. Tavily Extract
20
+ Allows agents to extract full content from specific URLs, including text and optionally images.
21
+
22
+ ## Configuration
23
+
24
+ To enable these skills, add the following to your agent configuration:
25
+
26
+ ```yaml
27
+ skills:
28
+ tavily:
29
+ enabled: true
30
+ api_key: "your-tavily-api-key"
31
+ states:
32
+ tavily_search: public # or "private" or "disabled"
33
+ tavily_extract: public # or "private" or "disabled"
34
+ ```
35
+
36
+ ### Configuration Options
37
+
38
+ - `enabled`: Whether the skills are enabled (true/false)
39
+ - `api_key`: Your Tavily API key
40
+ - `states.tavily_search`: The state of the Tavily search skill
41
+ - `public`: Available to agent owner and all users
42
+ - `private`: Available only to the agent owner
43
+ - `disabled`: Not available to anyone
44
+ - `states.tavily_extract`: The state of the Tavily extract skill
45
+ - `public`: Available to agent owner and all users
46
+ - `private`: Available only to the agent owner
47
+ - `disabled`: Not available to anyone
48
+
49
+ ## Usage Examples
50
+
51
+ ### Tavily Search
52
+
53
+ The agent will automatically use Tavily search when:
54
+ - A user asks for current information or news
55
+ - The agent needs to verify facts or find up-to-date information
56
+ - A query seeks information that may not be in the agent's training data
57
+
58
+ **Example Interaction:**
59
+
60
+ **User**: "What's the current price of Bitcoin?"
61
+
62
+ **Agent**: *Uses Tavily search to find current cryptocurrency prices*
63
+
64
+ ### Tavily Extract
65
+
66
+ The agent will automatically use Tavily extract when:
67
+ - A user wants to extract or scrape content from a specific URL
68
+ - The agent needs to analyze the full content of a web page
69
+ - A query requires detailed information from a particular website
70
+
71
+ **Example Interaction:**
72
+
73
+ **User**: "Can you extract the content from https://en.wikipedia.org/wiki/Artificial_intelligence"
74
+
75
+ **Agent**: *Uses Tavily extract to retrieve the full content from the Wikipedia page*
76
+
77
+ ## API Requirements
78
+
79
+ These skills require a valid Tavily API key. You can sign up for one at [tavily.com](https://tavily.com/).
80
+
81
+ ## Limitations
82
+
83
+ - Search results are limited to a maximum of 10 items per query
84
+ - Extract functionality may not work on all websites due to access restrictions
85
+ - The quality of results depends on the Tavily API
86
+ - Rate limits may apply based on your Tavily API plan
@@ -0,0 +1,91 @@
1
+ """Tavily search skills."""
2
+
3
+ import logging
4
+ from typing import TypedDict
5
+
6
+ from intentkit.abstracts.skill import SkillStoreABC
7
+ from intentkit.skills.base import SkillConfig, SkillState
8
+ from intentkit.skills.tavily.base import TavilyBaseTool
9
+ from intentkit.skills.tavily.tavily_extract import TavilyExtract
10
+ from intentkit.skills.tavily.tavily_search import TavilySearch
11
+
12
+ # Cache skills at the system level, because they are stateless
13
+ _cache: dict[str, TavilyBaseTool] = {}
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class SkillStates(TypedDict):
19
+ tavily_search: SkillState
20
+ tavily_extract: SkillState
21
+
22
+
23
+ class Config(SkillConfig):
24
+ """Configuration for Tavily search skills."""
25
+
26
+ states: SkillStates
27
+ api_key: str
28
+
29
+
30
+ async def get_skills(
31
+ config: "Config",
32
+ is_private: bool,
33
+ store: SkillStoreABC,
34
+ **_,
35
+ ) -> list[TavilyBaseTool]:
36
+ """Get all Tavily search skills.
37
+
38
+ Args:
39
+ config: The configuration for Tavily search skills.
40
+ is_private: Whether to include private skills.
41
+ store: The skill store for persisting data.
42
+
43
+ Returns:
44
+ A list of Tavily search skills.
45
+ """
46
+ available_skills = []
47
+
48
+ # Include skills based on their state
49
+ for skill_name, state in config["states"].items():
50
+ if state == "disabled":
51
+ continue
52
+ elif state == "public" or (state == "private" and is_private):
53
+ available_skills.append(skill_name)
54
+
55
+ # Get each skill using the cached getter
56
+ result = []
57
+ for name in available_skills:
58
+ skill = get_tavily_skill(name, store)
59
+ if skill:
60
+ result.append(skill)
61
+ return result
62
+
63
+
64
+ def get_tavily_skill(
65
+ name: str,
66
+ store: SkillStoreABC,
67
+ ) -> TavilyBaseTool:
68
+ """Get a Tavily search skill by name.
69
+
70
+ Args:
71
+ name: The name of the skill to get
72
+ store: The skill store for persisting data
73
+
74
+ Returns:
75
+ The requested Tavily search skill
76
+ """
77
+ if name == "tavily_search":
78
+ if name not in _cache:
79
+ _cache[name] = TavilySearch(
80
+ skill_store=store,
81
+ )
82
+ return _cache[name]
83
+ elif name == "tavily_extract":
84
+ if name not in _cache:
85
+ _cache[name] = TavilyExtract(
86
+ skill_store=store,
87
+ )
88
+ return _cache[name]
89
+ else:
90
+ logger.warning(f"Unknown Tavily skill: {name}")
91
+ return None
@@ -0,0 +1,27 @@
1
+ from typing import Type
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ from intentkit.abstracts.skill import SkillStoreABC
6
+ from intentkit.skills.base import IntentKitSkill, SkillContext
7
+
8
+
9
+ class TavilyBaseTool(IntentKitSkill):
10
+ """Base class for Tavily search tools."""
11
+
12
+ name: str = Field(description="The name of the tool")
13
+ description: str = Field(description="A description of what the tool does")
14
+ args_schema: Type[BaseModel]
15
+ skill_store: SkillStoreABC = Field(
16
+ description="The skill store for persisting data"
17
+ )
18
+
19
+ def get_api_key(self, context: SkillContext) -> str:
20
+ skill_config = context.config
21
+ if skill_config.get("api_key_provider") == "agent_owner":
22
+ return skill_config.get("api_key")
23
+ return self.skill_store.get_system_config("tavily_api_key")
24
+
25
+ @property
26
+ def category(self) -> str:
27
+ return "tavily"
@@ -0,0 +1,119 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "title": "Tavily Search and Extract",
5
+ "description": "Web search and content extraction capabilities using Tavily",
6
+ "x-icon": "https://ai.service.crestal.dev/skills/tavily/tavily.jpg",
7
+ "x-tags": [
8
+ "Internet",
9
+ "Search",
10
+ "Information",
11
+ "Content Extraction"
12
+ ],
13
+ "x-nft-requirement": 1,
14
+ "properties": {
15
+ "enabled": {
16
+ "type": "boolean",
17
+ "title": "Enabled",
18
+ "description": "Whether this skill is enabled",
19
+ "default": true
20
+ },
21
+ "states": {
22
+ "type": "object",
23
+ "properties": {
24
+ "tavily_search": {
25
+ "type": "string",
26
+ "title": "Tavily Search",
27
+ "enum": [
28
+ "disabled",
29
+ "public",
30
+ "private"
31
+ ],
32
+ "x-enum-title": [
33
+ "Disabled",
34
+ "Agent Owner + All Users",
35
+ "Agent Owner Only"
36
+ ],
37
+ "description": "Search the web for real-time information and recent content using Tavily",
38
+ "default": "private"
39
+ },
40
+ "tavily_extract": {
41
+ "type": "string",
42
+ "title": "Tavily Extract",
43
+ "enum": [
44
+ "disabled",
45
+ "public",
46
+ "private"
47
+ ],
48
+ "x-enum-title": [
49
+ "Disabled",
50
+ "Agent Owner + All Users",
51
+ "Agent Owner Only"
52
+ ],
53
+ "description": "Extract full content from web pages using Tavily Extract API",
54
+ "default": "private"
55
+ }
56
+ },
57
+ "description": "States for each Tavily skill (disabled, public, or private)"
58
+ },
59
+ "api_key_provider": {
60
+ "type": "string",
61
+ "title": "API Key Provider",
62
+ "description": "Provider of the API key",
63
+ "enum": [
64
+ "platform",
65
+ "agent_owner"
66
+ ],
67
+ "x-enum-title": [
68
+ "Nation Hosted",
69
+ "Owner Provided"
70
+ ],
71
+ "default": "platform"
72
+ }
73
+ },
74
+ "required": [
75
+ "states",
76
+ "enabled"
77
+ ],
78
+ "if": {
79
+ "properties": {
80
+ "api_key_provider": {
81
+ "const": "agent_owner"
82
+ }
83
+ }
84
+ },
85
+ "then": {
86
+ "properties": {
87
+ "api_key": {
88
+ "type": "string",
89
+ "title": "Tavily API Key",
90
+ "description": "API key for Tavily services",
91
+ "x-link": "[Get your API key](https://tavily.com/)",
92
+ "x-sensitive": true
93
+ },
94
+ "rate_limit_number": {
95
+ "type": "integer",
96
+ "title": "Rate Limit Number",
97
+ "description": "Number of requests allowed per time window, only valid if api_key is set"
98
+ },
99
+ "rate_limit_minutes": {
100
+ "type": "integer",
101
+ "title": "Rate Limit Minutes",
102
+ "description": "Time window in minutes for rate limiting, only valid if api_key is set"
103
+ }
104
+ },
105
+ "if": {
106
+ "properties": {
107
+ "enabled": {
108
+ "const": true
109
+ }
110
+ }
111
+ },
112
+ "then": {
113
+ "required": [
114
+ "api_key"
115
+ ]
116
+ }
117
+ },
118
+ "additionalProperties": true
119
+ }
Binary file
@@ -0,0 +1,147 @@
1
+ import logging
2
+ from typing import Type
3
+
4
+ import httpx
5
+ from langchain_core.runnables import RunnableConfig
6
+ from pydantic import BaseModel, Field
7
+
8
+ from intentkit.skills.tavily.base import TavilyBaseTool
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class TavilyExtractInput(BaseModel):
14
+ """Input for Tavily extract tool."""
15
+
16
+ urls: str = Field(
17
+ description="The URL to extract content from.",
18
+ )
19
+ include_images: bool = Field(
20
+ description="Include a list of images extracted from the URLs in the response.",
21
+ default=False,
22
+ )
23
+ extract_depth: str = Field(
24
+ description="The depth of the extraction process. 'advanced' retrieves more data including tables and embedded content with higher success but may increase latency. 'basic' costs 1 credit per 5 successful URL extractions, while 'advanced' costs 2 credits per 5 successful URL extractions.",
25
+ default="basic",
26
+ )
27
+
28
+
29
+ class TavilyExtract(TavilyBaseTool):
30
+ """Tool for extracting web page content using Tavily.
31
+
32
+ This tool uses Tavily's extract API to retrieve content from specified URLs.
33
+
34
+ Attributes:
35
+ name: The name of the tool.
36
+ description: A description of what the tool does.
37
+ args_schema: The schema for the tool's input arguments.
38
+ """
39
+
40
+ name: str = "tavily_extract"
41
+ description: str = (
42
+ "Extract web page content from a specified URL using Tavily Extract. "
43
+ "This tool is useful when you need to get the full text content from a webpage. "
44
+ "You must call this tool whenever the user asks to extract or scrape content from a specific URL."
45
+ )
46
+ args_schema: Type[BaseModel] = TavilyExtractInput
47
+
48
+ async def _arun(
49
+ self,
50
+ urls: str,
51
+ include_images: bool = False,
52
+ extract_depth: str = "basic",
53
+ config: RunnableConfig = None,
54
+ **kwargs,
55
+ ) -> str:
56
+ """Implementation of the Tavily extract tool.
57
+
58
+ Args:
59
+ urls: The URL to extract content from.
60
+ include_images: Whether to include image URLs in the results.
61
+ extract_depth: The depth of the extraction process ('basic' or 'advanced').
62
+ config: The configuration for the tool call.
63
+
64
+ Returns:
65
+ str: Formatted extraction results with content from the URL.
66
+ """
67
+ context = self.context_from_config(config)
68
+ logger.debug(
69
+ f"tavily_extract.py: Running web extraction with context {context}"
70
+ )
71
+
72
+ if context.config.get("api_key_provider") == "agent_owner":
73
+ if context.config.get("rate_limit_number") and context.config.get(
74
+ "rate_limit_minutes"
75
+ ):
76
+ await self.user_rate_limit_by_category(
77
+ context.user_id,
78
+ context.config["rate_limit_number"],
79
+ context.config["rate_limit_minutes"],
80
+ )
81
+
82
+ # Get the API key from the agent's configuration
83
+ api_key = self.get_api_key(context)
84
+ if not api_key:
85
+ return "Error: No Tavily API key provided in the configuration."
86
+
87
+ # Validate extract_depth
88
+ if extract_depth not in ["basic", "advanced"]:
89
+ extract_depth = "basic"
90
+ logger.warning(
91
+ "tavily_extract.py: Invalid extract_depth provided. Using default 'basic'."
92
+ )
93
+
94
+ # Call Tavily extract API
95
+ try:
96
+ async with httpx.AsyncClient(timeout=30.0) as client:
97
+ response = await client.post(
98
+ "https://api.tavily.com/extract",
99
+ headers={"Authorization": f"Bearer {api_key}"},
100
+ json={
101
+ "urls": urls,
102
+ "include_images": include_images,
103
+ "extract_depth": extract_depth,
104
+ },
105
+ )
106
+
107
+ if response.status_code != 200:
108
+ logger.error(
109
+ f"tavily_extract.py: Error from Tavily API: {response.status_code} - {response.text}"
110
+ )
111
+ return f"Error extracting web page content: {response.status_code} - {response.text}"
112
+
113
+ data = response.json()
114
+ results = data.get("results", [])
115
+
116
+ if not results:
117
+ return f"No content could be extracted from URL: '{urls}'"
118
+
119
+ # Format the results
120
+ formatted_results = f"Web page content extracted from: '{urls}'\n\n"
121
+
122
+ for i, result in enumerate(results, 1):
123
+ url = result.get("url", "No URL")
124
+ raw_content = result.get("raw_content", "No content available")
125
+
126
+ # Truncate the content if it's too long (over 2000 characters)
127
+ if len(raw_content) > 2000:
128
+ raw_content = raw_content[:2000] + "...[content truncated]"
129
+
130
+ formatted_results += f"{i}. Content from {url}:\n\n"
131
+ formatted_results += f"{raw_content}\n\n"
132
+
133
+ # Add images if available and requested
134
+ if include_images and "images" in result and result["images"]:
135
+ formatted_results += "Images:\n"
136
+ for j, image_url in enumerate(result["images"], 1):
137
+ formatted_results += f" {j}. {image_url}\n"
138
+ formatted_results += "\n"
139
+
140
+ return formatted_results.strip()
141
+
142
+ except Exception as e:
143
+ logger.error(
144
+ f"tavily_extract.py: Error extracting web page content: {e}",
145
+ exc_info=True,
146
+ )
147
+ return "An error occurred while extracting web page content. Please try again later."
@@ -0,0 +1,139 @@
1
+ import logging
2
+ from typing import Type
3
+
4
+ import httpx
5
+ from langchain_core.runnables import RunnableConfig
6
+ from pydantic import BaseModel, Field
7
+
8
+ from intentkit.skills.tavily.base import TavilyBaseTool
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class TavilySearchInput(BaseModel):
14
+ """Input for Tavily search tool."""
15
+
16
+ query: str = Field(
17
+ description="The search query to look up on the web.",
18
+ )
19
+ max_results: int = Field(
20
+ description="Maximum number of search results to return (1-10).",
21
+ default=5,
22
+ ge=1,
23
+ le=10,
24
+ )
25
+ include_images: bool = Field(
26
+ description="Whether to include image URLs in the results.",
27
+ default=False,
28
+ )
29
+ include_raw_content: bool = Field(
30
+ description="Whether to include raw HTML content in the results.",
31
+ default=False,
32
+ )
33
+
34
+
35
+ class TavilySearch(TavilyBaseTool):
36
+ """Tool for searching the web using Tavily.
37
+
38
+ This tool uses Tavily's search API to search the web and return relevant results.
39
+
40
+ Attributes:
41
+ name: The name of the tool.
42
+ description: A description of what the tool does.
43
+ args_schema: The schema for the tool's input arguments.
44
+ """
45
+
46
+ name: str = "tavily_search"
47
+ description: str = (
48
+ "Search the web for current information on a topic. Use this tool when you need to find"
49
+ " up-to-date information, facts, news, or any content available online.\n"
50
+ "You must call this tool whenever the user asks for information that may not be in your training data,"
51
+ " requires current data, or when you're unsure about facts."
52
+ )
53
+ args_schema: Type[BaseModel] = TavilySearchInput
54
+
55
+ async def _arun(
56
+ self,
57
+ query: str,
58
+ max_results: int = 5,
59
+ include_images: bool = False,
60
+ include_raw_content: bool = False,
61
+ config: RunnableConfig = None,
62
+ **kwargs,
63
+ ) -> str:
64
+ """Implementation of the Tavily search tool.
65
+
66
+ Args:
67
+ query: The search query to look up.
68
+ max_results: Maximum number of search results to return (1-10).
69
+ include_images: Whether to include image URLs in the results.
70
+ include_raw_content: Whether to include raw HTML content in the results.
71
+ config: The configuration for the tool call.
72
+
73
+ Returns:
74
+ str: Formatted search results with titles, snippets, and URLs.
75
+ """
76
+ context = self.context_from_config(config)
77
+ logger.debug(f"tavily.py: Running web search with context {context}")
78
+
79
+ if context.config.get("api_key_provider") == "agent_owner":
80
+ if context.config.get("rate_limit_number") and context.config.get(
81
+ "rate_limit_minutes"
82
+ ):
83
+ await self.user_rate_limit_by_category(
84
+ context.user_id,
85
+ context.config["rate_limit_number"],
86
+ context.config["rate_limit_minutes"],
87
+ )
88
+
89
+ # Get the API key from the agent's configuration
90
+ api_key = self.get_api_key(context)
91
+ if not api_key:
92
+ return "Error: No Tavily API key provided in the configuration."
93
+
94
+ # Limit max_results to a reasonable range
95
+ max_results = max(1, min(max_results, 10))
96
+
97
+ # Call Tavily search API
98
+ try:
99
+ async with httpx.AsyncClient(timeout=30.0) as client:
100
+ response = await client.post(
101
+ "https://api.tavily.com/search",
102
+ json={
103
+ "api_key": api_key,
104
+ "query": query,
105
+ "max_results": max_results,
106
+ "include_images": include_images,
107
+ "include_raw_content": include_raw_content,
108
+ },
109
+ )
110
+
111
+ if response.status_code != 200:
112
+ logger.error(
113
+ f"tavily.py: Error from Tavily API: {response.status_code} - {response.text}"
114
+ )
115
+ return f"Error searching the web: {response.status_code} - {response.text}"
116
+
117
+ data = response.json()
118
+ results = data.get("results", [])
119
+
120
+ if not results:
121
+ return f"No results found for query: '{query}'"
122
+
123
+ # Format the results
124
+ formatted_results = f"Web search results for: '{query}'\n\n"
125
+
126
+ for i, result in enumerate(results, 1):
127
+ title = result.get("title", "No title")
128
+ content = result.get("content", "No content")
129
+ url = result.get("url", "No URL")
130
+
131
+ formatted_results += f"{i}. {title}\n"
132
+ formatted_results += f"{content}\n"
133
+ formatted_results += f"Source: {url}\n\n"
134
+
135
+ return formatted_results.strip()
136
+
137
+ except Exception as e:
138
+ logger.error(f"tavily.py: Error searching web: {e}", exc_info=True)
139
+ return "An error occurred while searching the web. Please try again later."