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.
- intentkit/__init__.py +17 -0
- intentkit/abstracts/__init__.py +0 -0
- intentkit/abstracts/agent.py +60 -0
- intentkit/abstracts/api.py +4 -0
- intentkit/abstracts/engine.py +38 -0
- intentkit/abstracts/exception.py +9 -0
- intentkit/abstracts/graph.py +25 -0
- intentkit/abstracts/skill.py +129 -0
- intentkit/abstracts/twitter.py +54 -0
- intentkit/clients/__init__.py +14 -0
- intentkit/clients/cdp.py +53 -0
- intentkit/clients/twitter.py +445 -0
- intentkit/config/__init__.py +0 -0
- intentkit/config/config.py +164 -0
- intentkit/core/__init__.py +0 -0
- intentkit/core/agent.py +191 -0
- intentkit/core/api.py +40 -0
- intentkit/core/client.py +45 -0
- intentkit/core/credit.py +1767 -0
- intentkit/core/engine.py +1018 -0
- intentkit/core/node.py +223 -0
- intentkit/core/prompt.py +58 -0
- intentkit/core/skill.py +124 -0
- intentkit/models/agent.py +1689 -0
- intentkit/models/agent_data.py +810 -0
- intentkit/models/agent_schema.json +733 -0
- intentkit/models/app_setting.py +156 -0
- intentkit/models/base.py +9 -0
- intentkit/models/chat.py +581 -0
- intentkit/models/conversation.py +286 -0
- intentkit/models/credit.py +1406 -0
- intentkit/models/db.py +120 -0
- intentkit/models/db_mig.py +102 -0
- intentkit/models/generator.py +347 -0
- intentkit/models/llm.py +746 -0
- intentkit/models/redis.py +132 -0
- intentkit/models/skill.py +466 -0
- intentkit/models/user.py +243 -0
- intentkit/skills/__init__.py +12 -0
- intentkit/skills/acolyt/__init__.py +83 -0
- intentkit/skills/acolyt/acolyt.jpg +0 -0
- intentkit/skills/acolyt/ask.py +128 -0
- intentkit/skills/acolyt/base.py +28 -0
- intentkit/skills/acolyt/schema.json +89 -0
- intentkit/skills/aixbt/README.md +71 -0
- intentkit/skills/aixbt/__init__.py +73 -0
- intentkit/skills/aixbt/aixbt.jpg +0 -0
- intentkit/skills/aixbt/base.py +21 -0
- intentkit/skills/aixbt/projects.py +153 -0
- intentkit/skills/aixbt/schema.json +99 -0
- intentkit/skills/allora/__init__.py +83 -0
- intentkit/skills/allora/allora.jpeg +0 -0
- intentkit/skills/allora/base.py +28 -0
- intentkit/skills/allora/price.py +130 -0
- intentkit/skills/allora/schema.json +89 -0
- intentkit/skills/base.py +174 -0
- intentkit/skills/carv/README.md +95 -0
- intentkit/skills/carv/__init__.py +121 -0
- intentkit/skills/carv/base.py +183 -0
- intentkit/skills/carv/carv.webp +0 -0
- intentkit/skills/carv/fetch_news.py +92 -0
- intentkit/skills/carv/onchain_query.py +164 -0
- intentkit/skills/carv/schema.json +137 -0
- intentkit/skills/carv/token_info_and_price.py +110 -0
- intentkit/skills/cdp/__init__.py +137 -0
- intentkit/skills/cdp/base.py +21 -0
- intentkit/skills/cdp/cdp.png +0 -0
- intentkit/skills/cdp/get_balance.py +81 -0
- intentkit/skills/cdp/schema.json +473 -0
- intentkit/skills/chainlist/README.md +38 -0
- intentkit/skills/chainlist/__init__.py +54 -0
- intentkit/skills/chainlist/base.py +21 -0
- intentkit/skills/chainlist/chain_lookup.py +208 -0
- intentkit/skills/chainlist/chainlist.png +0 -0
- intentkit/skills/chainlist/schema.json +47 -0
- intentkit/skills/common/__init__.py +82 -0
- intentkit/skills/common/base.py +21 -0
- intentkit/skills/common/common.jpg +0 -0
- intentkit/skills/common/current_time.py +84 -0
- intentkit/skills/common/schema.json +57 -0
- intentkit/skills/cookiefun/README.md +121 -0
- intentkit/skills/cookiefun/__init__.py +78 -0
- intentkit/skills/cookiefun/base.py +41 -0
- intentkit/skills/cookiefun/constants.py +18 -0
- intentkit/skills/cookiefun/cookiefun.png +0 -0
- intentkit/skills/cookiefun/get_account_details.py +171 -0
- intentkit/skills/cookiefun/get_account_feed.py +282 -0
- intentkit/skills/cookiefun/get_account_smart_followers.py +181 -0
- intentkit/skills/cookiefun/get_sectors.py +128 -0
- intentkit/skills/cookiefun/schema.json +155 -0
- intentkit/skills/cookiefun/search_accounts.py +225 -0
- intentkit/skills/cryptocompare/__init__.py +130 -0
- intentkit/skills/cryptocompare/api.py +159 -0
- intentkit/skills/cryptocompare/base.py +303 -0
- intentkit/skills/cryptocompare/cryptocompare.png +0 -0
- intentkit/skills/cryptocompare/fetch_news.py +96 -0
- intentkit/skills/cryptocompare/fetch_price.py +99 -0
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +113 -0
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +109 -0
- intentkit/skills/cryptocompare/fetch_top_volume.py +108 -0
- intentkit/skills/cryptocompare/fetch_trading_signals.py +107 -0
- intentkit/skills/cryptocompare/schema.json +168 -0
- intentkit/skills/cryptopanic/__init__.py +108 -0
- intentkit/skills/cryptopanic/base.py +51 -0
- intentkit/skills/cryptopanic/cryptopanic.png +0 -0
- intentkit/skills/cryptopanic/fetch_crypto_news.py +153 -0
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +136 -0
- intentkit/skills/cryptopanic/schema.json +103 -0
- intentkit/skills/dapplooker/README.md +92 -0
- intentkit/skills/dapplooker/__init__.py +83 -0
- intentkit/skills/dapplooker/base.py +26 -0
- intentkit/skills/dapplooker/dapplooker.jpg +0 -0
- intentkit/skills/dapplooker/dapplooker_token_data.py +476 -0
- intentkit/skills/dapplooker/schema.json +91 -0
- intentkit/skills/defillama/__init__.py +323 -0
- intentkit/skills/defillama/api.py +315 -0
- intentkit/skills/defillama/base.py +135 -0
- intentkit/skills/defillama/coins/__init__.py +0 -0
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +116 -0
- intentkit/skills/defillama/coins/fetch_block.py +98 -0
- intentkit/skills/defillama/coins/fetch_current_prices.py +105 -0
- intentkit/skills/defillama/coins/fetch_first_price.py +100 -0
- intentkit/skills/defillama/coins/fetch_historical_prices.py +110 -0
- intentkit/skills/defillama/coins/fetch_price_chart.py +109 -0
- intentkit/skills/defillama/coins/fetch_price_percentage.py +93 -0
- intentkit/skills/defillama/config/__init__.py +0 -0
- intentkit/skills/defillama/config/chains.py +433 -0
- intentkit/skills/defillama/defillama.jpeg +0 -0
- intentkit/skills/defillama/fees/__init__.py +0 -0
- intentkit/skills/defillama/fees/fetch_fees_overview.py +130 -0
- intentkit/skills/defillama/schema.json +383 -0
- intentkit/skills/defillama/stablecoins/__init__.py +0 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +100 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +129 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +83 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +126 -0
- intentkit/skills/defillama/tests/__init__.py +0 -0
- intentkit/skills/defillama/tests/api_integration.test.py +192 -0
- intentkit/skills/defillama/tests/api_unit.test.py +583 -0
- intentkit/skills/defillama/tvl/__init__.py +0 -0
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +106 -0
- intentkit/skills/defillama/tvl/fetch_chains.py +107 -0
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +91 -0
- intentkit/skills/defillama/tvl/fetch_protocol.py +207 -0
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +93 -0
- intentkit/skills/defillama/tvl/fetch_protocols.py +196 -0
- intentkit/skills/defillama/volumes/__init__.py +0 -0
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +157 -0
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +123 -0
- intentkit/skills/defillama/volumes/fetch_options_overview.py +131 -0
- intentkit/skills/defillama/yields/__init__.py +0 -0
- intentkit/skills/defillama/yields/fetch_pool_chart.py +100 -0
- intentkit/skills/defillama/yields/fetch_pools.py +126 -0
- intentkit/skills/dexscreener/__init__.py +93 -0
- intentkit/skills/dexscreener/base.py +133 -0
- intentkit/skills/dexscreener/dexscreener.png +0 -0
- intentkit/skills/dexscreener/model/__init__.py +0 -0
- intentkit/skills/dexscreener/model/search_token_response.py +82 -0
- intentkit/skills/dexscreener/schema.json +48 -0
- intentkit/skills/dexscreener/search_token.py +321 -0
- intentkit/skills/dune_analytics/__init__.py +103 -0
- intentkit/skills/dune_analytics/base.py +46 -0
- intentkit/skills/dune_analytics/dune.png +0 -0
- intentkit/skills/dune_analytics/fetch_kol_buys.py +128 -0
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +237 -0
- intentkit/skills/dune_analytics/schema.json +99 -0
- intentkit/skills/elfa/README.md +100 -0
- intentkit/skills/elfa/__init__.py +123 -0
- intentkit/skills/elfa/base.py +28 -0
- intentkit/skills/elfa/elfa.jpg +0 -0
- intentkit/skills/elfa/mention.py +504 -0
- intentkit/skills/elfa/schema.json +153 -0
- intentkit/skills/elfa/stats.py +118 -0
- intentkit/skills/elfa/tokens.py +126 -0
- intentkit/skills/enso/README.md +75 -0
- intentkit/skills/enso/__init__.py +114 -0
- intentkit/skills/enso/abi/__init__.py +0 -0
- intentkit/skills/enso/abi/approval.py +279 -0
- intentkit/skills/enso/abi/erc20.py +14 -0
- intentkit/skills/enso/abi/route.py +129 -0
- intentkit/skills/enso/base.py +44 -0
- intentkit/skills/enso/best_yield.py +286 -0
- intentkit/skills/enso/enso.jpg +0 -0
- intentkit/skills/enso/networks.py +105 -0
- intentkit/skills/enso/prices.py +93 -0
- intentkit/skills/enso/route.py +300 -0
- intentkit/skills/enso/schema.json +212 -0
- intentkit/skills/enso/tokens.py +223 -0
- intentkit/skills/enso/wallet.py +381 -0
- intentkit/skills/github/README.md +63 -0
- intentkit/skills/github/__init__.py +54 -0
- intentkit/skills/github/base.py +21 -0
- intentkit/skills/github/github.jpg +0 -0
- intentkit/skills/github/github_search.py +183 -0
- intentkit/skills/github/schema.json +59 -0
- intentkit/skills/heurist/__init__.py +143 -0
- intentkit/skills/heurist/base.py +26 -0
- intentkit/skills/heurist/heurist.png +0 -0
- intentkit/skills/heurist/image_generation_animagine_xl.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_comics.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_real.py +162 -0
- intentkit/skills/heurist/image_generation_braindance.py +162 -0
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +162 -0
- intentkit/skills/heurist/image_generation_flux_1_dev.py +162 -0
- intentkit/skills/heurist/image_generation_sdxl.py +161 -0
- intentkit/skills/heurist/schema.json +196 -0
- intentkit/skills/lifi/README.md +294 -0
- intentkit/skills/lifi/__init__.py +141 -0
- intentkit/skills/lifi/base.py +21 -0
- intentkit/skills/lifi/lifi.png +0 -0
- intentkit/skills/lifi/schema.json +89 -0
- intentkit/skills/lifi/token_execute.py +472 -0
- intentkit/skills/lifi/token_quote.py +190 -0
- intentkit/skills/lifi/utils.py +656 -0
- intentkit/skills/moralis/README.md +490 -0
- intentkit/skills/moralis/__init__.py +110 -0
- intentkit/skills/moralis/api.py +281 -0
- intentkit/skills/moralis/base.py +55 -0
- intentkit/skills/moralis/fetch_chain_portfolio.py +191 -0
- intentkit/skills/moralis/fetch_nft_portfolio.py +284 -0
- intentkit/skills/moralis/fetch_solana_portfolio.py +331 -0
- intentkit/skills/moralis/fetch_wallet_portfolio.py +301 -0
- intentkit/skills/moralis/moralis.png +0 -0
- intentkit/skills/moralis/schema.json +156 -0
- intentkit/skills/moralis/tests/__init__.py +0 -0
- intentkit/skills/moralis/tests/test_wallet.py +511 -0
- intentkit/skills/nation/__init__.py +62 -0
- intentkit/skills/nation/base.py +31 -0
- intentkit/skills/nation/nation.png +0 -0
- intentkit/skills/nation/nft_check.py +106 -0
- intentkit/skills/nation/schema.json +58 -0
- intentkit/skills/openai/__init__.py +107 -0
- intentkit/skills/openai/base.py +32 -0
- intentkit/skills/openai/dalle_image_generation.py +128 -0
- intentkit/skills/openai/gpt_image_generation.py +152 -0
- intentkit/skills/openai/gpt_image_to_image.py +186 -0
- intentkit/skills/openai/image_to_text.py +126 -0
- intentkit/skills/openai/openai.png +0 -0
- intentkit/skills/openai/schema.json +139 -0
- intentkit/skills/portfolio/README.md +55 -0
- intentkit/skills/portfolio/__init__.py +151 -0
- intentkit/skills/portfolio/base.py +107 -0
- intentkit/skills/portfolio/constants.py +9 -0
- intentkit/skills/portfolio/moralis.png +0 -0
- intentkit/skills/portfolio/schema.json +237 -0
- intentkit/skills/portfolio/token_balances.py +155 -0
- intentkit/skills/portfolio/wallet_approvals.py +102 -0
- intentkit/skills/portfolio/wallet_defi_positions.py +80 -0
- intentkit/skills/portfolio/wallet_history.py +155 -0
- intentkit/skills/portfolio/wallet_net_worth.py +112 -0
- intentkit/skills/portfolio/wallet_nfts.py +139 -0
- intentkit/skills/portfolio/wallet_profitability.py +101 -0
- intentkit/skills/portfolio/wallet_profitability_summary.py +91 -0
- intentkit/skills/portfolio/wallet_stats.py +79 -0
- intentkit/skills/portfolio/wallet_swaps.py +147 -0
- intentkit/skills/skills.toml +103 -0
- intentkit/skills/slack/__init__.py +98 -0
- intentkit/skills/slack/base.py +55 -0
- intentkit/skills/slack/get_channel.py +109 -0
- intentkit/skills/slack/get_message.py +136 -0
- intentkit/skills/slack/schedule_message.py +92 -0
- intentkit/skills/slack/schema.json +135 -0
- intentkit/skills/slack/send_message.py +81 -0
- intentkit/skills/slack/slack.jpg +0 -0
- intentkit/skills/system/__init__.py +90 -0
- intentkit/skills/system/base.py +22 -0
- intentkit/skills/system/read_agent_api_key.py +87 -0
- intentkit/skills/system/regenerate_agent_api_key.py +77 -0
- intentkit/skills/system/schema.json +53 -0
- intentkit/skills/system/system.svg +76 -0
- intentkit/skills/tavily/README.md +86 -0
- intentkit/skills/tavily/__init__.py +91 -0
- intentkit/skills/tavily/base.py +27 -0
- intentkit/skills/tavily/schema.json +119 -0
- intentkit/skills/tavily/tavily.jpg +0 -0
- intentkit/skills/tavily/tavily_extract.py +147 -0
- intentkit/skills/tavily/tavily_search.py +139 -0
- intentkit/skills/token/README.md +89 -0
- intentkit/skills/token/__init__.py +107 -0
- intentkit/skills/token/base.py +154 -0
- intentkit/skills/token/constants.py +9 -0
- intentkit/skills/token/erc20_transfers.py +145 -0
- intentkit/skills/token/moralis.png +0 -0
- intentkit/skills/token/schema.json +141 -0
- intentkit/skills/token/token_analytics.py +81 -0
- intentkit/skills/token/token_price.py +132 -0
- intentkit/skills/token/token_search.py +121 -0
- intentkit/skills/twitter/__init__.py +146 -0
- intentkit/skills/twitter/base.py +68 -0
- intentkit/skills/twitter/follow_user.py +69 -0
- intentkit/skills/twitter/get_mentions.py +124 -0
- intentkit/skills/twitter/get_timeline.py +111 -0
- intentkit/skills/twitter/get_user_by_username.py +84 -0
- intentkit/skills/twitter/get_user_tweets.py +123 -0
- intentkit/skills/twitter/like_tweet.py +65 -0
- intentkit/skills/twitter/post_tweet.py +90 -0
- intentkit/skills/twitter/reply_tweet.py +98 -0
- intentkit/skills/twitter/retweet.py +76 -0
- intentkit/skills/twitter/schema.json +258 -0
- intentkit/skills/twitter/search_tweets.py +115 -0
- intentkit/skills/twitter/twitter.png +0 -0
- intentkit/skills/unrealspeech/__init__.py +55 -0
- intentkit/skills/unrealspeech/base.py +21 -0
- intentkit/skills/unrealspeech/schema.json +100 -0
- intentkit/skills/unrealspeech/text_to_speech.py +177 -0
- intentkit/skills/unrealspeech/unrealspeech.jpg +0 -0
- intentkit/skills/venice_audio/__init__.py +106 -0
- intentkit/skills/venice_audio/base.py +119 -0
- intentkit/skills/venice_audio/input.py +41 -0
- intentkit/skills/venice_audio/schema.json +152 -0
- intentkit/skills/venice_audio/venice_audio.py +240 -0
- intentkit/skills/venice_audio/venice_logo.jpg +0 -0
- intentkit/skills/venice_image/README.md +119 -0
- intentkit/skills/venice_image/__init__.py +154 -0
- intentkit/skills/venice_image/api.py +138 -0
- intentkit/skills/venice_image/base.py +188 -0
- intentkit/skills/venice_image/config.py +35 -0
- intentkit/skills/venice_image/image_enhance/README.md +119 -0
- intentkit/skills/venice_image/image_enhance/__init__.py +0 -0
- intentkit/skills/venice_image/image_enhance/image_enhance.py +80 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_base.py +23 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_input.py +40 -0
- intentkit/skills/venice_image/image_generation/README.md +144 -0
- intentkit/skills/venice_image/image_generation/__init__.py +0 -0
- intentkit/skills/venice_image/image_generation/image_generation_base.py +117 -0
- intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -0
- intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -0
- intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -0
- intentkit/skills/venice_image/image_upscale/README.md +111 -0
- intentkit/skills/venice_image/image_upscale/__init__.py +0 -0
- intentkit/skills/venice_image/image_upscale/image_upscale.py +90 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_base.py +23 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -0
- intentkit/skills/venice_image/image_vision/README.md +112 -0
- intentkit/skills/venice_image/image_vision/__init__.py +0 -0
- intentkit/skills/venice_image/image_vision/image_vision.py +100 -0
- intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -0
- intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -0
- intentkit/skills/venice_image/schema.json +267 -0
- intentkit/skills/venice_image/utils.py +78 -0
- intentkit/skills/venice_image/venice_image.jpg +0 -0
- intentkit/skills/web_scraper/README.md +82 -0
- intentkit/skills/web_scraper/__init__.py +92 -0
- intentkit/skills/web_scraper/base.py +21 -0
- intentkit/skills/web_scraper/langchain.png +0 -0
- intentkit/skills/web_scraper/schema.json +115 -0
- intentkit/skills/web_scraper/scrape_and_index.py +327 -0
- intentkit/utils/__init__.py +1 -0
- intentkit/utils/chain.py +436 -0
- intentkit/utils/error.py +134 -0
- intentkit/utils/logging.py +70 -0
- intentkit/utils/middleware.py +61 -0
- intentkit/utils/random.py +16 -0
- intentkit/utils/s3.py +267 -0
- intentkit/utils/slack_alert.py +79 -0
- intentkit/utils/tx.py +37 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/METADATA +1 -1
- intentkit-0.5.2.dist-info/RECORD +365 -0
- intentkit-0.5.0.dist-info/RECORD +0 -4
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/WHEEL +0 -0
- {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."
|