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,103 @@
|
|
|
1
|
+
"""Dune Analytics skill module for IntentKit.
|
|
2
|
+
|
|
3
|
+
Loads and initializes skills for fetching data from Dune Analytics API.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Dict, List, Optional, TypedDict
|
|
8
|
+
|
|
9
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
10
|
+
from intentkit.skills.base import SkillConfig, SkillState
|
|
11
|
+
from intentkit.skills.dune_analytics.base import DuneBaseTool
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
# Cache for skill instances
|
|
16
|
+
_skill_cache: Dict[str, DuneBaseTool] = {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SkillStates(TypedDict):
|
|
20
|
+
"""Type definition for Dune Analytics skill states."""
|
|
21
|
+
|
|
22
|
+
fetch_nation_metrics: SkillState
|
|
23
|
+
fetch_kol_buys: SkillState
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Config(SkillConfig):
|
|
27
|
+
"""Configuration schema for Dune Analytics skills."""
|
|
28
|
+
|
|
29
|
+
states: SkillStates
|
|
30
|
+
api_key: str
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def get_skills(
|
|
34
|
+
config: Config,
|
|
35
|
+
is_private: bool,
|
|
36
|
+
store: SkillStoreABC,
|
|
37
|
+
**kwargs,
|
|
38
|
+
) -> List[DuneBaseTool]:
|
|
39
|
+
"""Load Dune Analytics skills based on configuration.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
config: Skill configuration with states and API key.
|
|
43
|
+
is_private: Whether the context is private (affects skill visibility).
|
|
44
|
+
store: Skill store for accessing other skills.
|
|
45
|
+
**kwargs: Additional keyword arguments.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
List of loaded Dune Analytics skill instances.
|
|
49
|
+
"""
|
|
50
|
+
logger.info("Loading Dune Analytics skills")
|
|
51
|
+
available_skills = []
|
|
52
|
+
|
|
53
|
+
for skill_name, state in config["states"].items():
|
|
54
|
+
logger.debug("Checking skill: %s, state: %s", skill_name, state)
|
|
55
|
+
if state == "disabled":
|
|
56
|
+
continue
|
|
57
|
+
if state == "public" or (state == "private" and is_private):
|
|
58
|
+
available_skills.append(skill_name)
|
|
59
|
+
|
|
60
|
+
loaded_skills = []
|
|
61
|
+
for name in available_skills:
|
|
62
|
+
skill = get_dune_skill(name, store)
|
|
63
|
+
if skill:
|
|
64
|
+
logger.info("Successfully loaded skill: %s", name)
|
|
65
|
+
loaded_skills.append(skill)
|
|
66
|
+
else:
|
|
67
|
+
logger.warning("Failed to load skill: %s", name)
|
|
68
|
+
|
|
69
|
+
return loaded_skills
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_dune_skill(name: str, store: SkillStoreABC) -> Optional[DuneBaseTool]:
|
|
73
|
+
"""Retrieve a Dune Analytics skill instance by name.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
name: Name of the skill (e.g., 'fetch_nation_metrics', 'fetch_kol_buys').
|
|
77
|
+
store: Skill store for accessing other skills.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Dune Analytics skill instance or None if not found or import fails.
|
|
81
|
+
"""
|
|
82
|
+
if name in _skill_cache:
|
|
83
|
+
logger.debug("Retrieved cached skill: %s", name)
|
|
84
|
+
return _skill_cache[name]
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
if name == "fetch_nation_metrics":
|
|
88
|
+
from .fetch_nation_metrics import FetchNationMetrics
|
|
89
|
+
|
|
90
|
+
_skill_cache[name] = FetchNationMetrics(skill_store=store)
|
|
91
|
+
elif name == "fetch_kol_buys":
|
|
92
|
+
from .fetch_kol_buys import FetchKOLBuys
|
|
93
|
+
|
|
94
|
+
_skill_cache[name] = FetchKOLBuys(skill_store=store)
|
|
95
|
+
else:
|
|
96
|
+
logger.warning("Unknown Dune Analytics skill: %s", name)
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
logger.debug("Cached new skill instance: %s", name)
|
|
100
|
+
return _skill_cache[name]
|
|
101
|
+
except ImportError as e:
|
|
102
|
+
logger.error("Failed to import skill %s: %s", name, e)
|
|
103
|
+
return None
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Base module for Dune Analytics skills.
|
|
2
|
+
|
|
3
|
+
Provides shared functionality for interacting with the Dune Analytics API.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Type
|
|
7
|
+
|
|
8
|
+
from langchain.tools.base import ToolException
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
12
|
+
from intentkit.skills.base import IntentKitSkill, SkillContext
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DuneBaseTool(IntentKitSkill):
|
|
16
|
+
"""Base class for Dune Analytics skills.
|
|
17
|
+
|
|
18
|
+
Offers common functionality like API key retrieval and Dune API interaction.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
name: str = Field(description="Tool name")
|
|
22
|
+
description: str = Field(description="Tool description")
|
|
23
|
+
args_schema: Type[BaseModel]
|
|
24
|
+
skill_store: SkillStoreABC = Field(description="Skill store for data persistence")
|
|
25
|
+
|
|
26
|
+
def get_api_key(self, context: SkillContext) -> str:
|
|
27
|
+
"""Retrieve the Dune Analytics API key from context.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
context: Skill context containing configuration.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
API key string.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
ToolException: If the API key is not found.
|
|
37
|
+
"""
|
|
38
|
+
api_key = context.config.get("api_key")
|
|
39
|
+
if not api_key:
|
|
40
|
+
raise ToolException("Dune API key not found in context.config['api_key']")
|
|
41
|
+
return api_key
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def category(self) -> str:
|
|
45
|
+
"""Category of the skill."""
|
|
46
|
+
return "dune_analytics"
|
|
Binary file
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Skill to fetch KOL memecoin buys on Solana from Dune Analytics API.
|
|
2
|
+
|
|
3
|
+
Uses query ID 4832844 to retrieve a list of KOL buy transactions.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any, Dict, Type
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
from langchain_core.runnables import RunnableConfig
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
from tenacity import retry, stop_after_attempt, wait_exponential
|
|
12
|
+
|
|
13
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
14
|
+
from intentkit.skills.dune_analytics.base import DuneBaseTool
|
|
15
|
+
|
|
16
|
+
BASE_URL = "https://api.dune.com/api/v1/query"
|
|
17
|
+
KOL_BUYS_QUERY_ID = 4832844
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class KOLBuysInput(BaseModel):
|
|
21
|
+
"""Input schema for fetching KOL memecoin buys."""
|
|
22
|
+
|
|
23
|
+
limit: int = Field(
|
|
24
|
+
default=10,
|
|
25
|
+
description="Maximum number of buy transactions to fetch (default 10).",
|
|
26
|
+
ge=1,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class KOLBuyData(BaseModel):
|
|
31
|
+
"""Data model for KOL buy results."""
|
|
32
|
+
|
|
33
|
+
data: Dict[str, Any] = Field(description="KOL buy data from Dune API")
|
|
34
|
+
error: str = Field(default="", description="Error message if fetch failed")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class KOLBuysOutput(BaseModel):
|
|
38
|
+
"""Output schema for KOL memecoin buys."""
|
|
39
|
+
|
|
40
|
+
buys: KOLBuyData = Field(description="KOL buy transaction data")
|
|
41
|
+
summary: str = Field(description="Summary of fetched data")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class FetchKOLBuys(DuneBaseTool):
|
|
45
|
+
"""Skill to fetch KOL memecoin buys on Solana from Dune Analytics API."""
|
|
46
|
+
|
|
47
|
+
name: str = "dune_fetch_kol_buys"
|
|
48
|
+
description: str = (
|
|
49
|
+
"Fetches a list of KOL memecoin buy transactions on Solana from Dune Analytics API using query ID 4832844. "
|
|
50
|
+
"Supports a configurable limit for the number of results. Handles rate limits with retries."
|
|
51
|
+
)
|
|
52
|
+
args_schema: Type[BaseModel] = KOLBuysInput
|
|
53
|
+
skill_store: SkillStoreABC = Field(description="Skill store for data persistence")
|
|
54
|
+
|
|
55
|
+
@retry(
|
|
56
|
+
stop=stop_after_attempt(3), wait=wait_exponential(multiplier=5, min=5, max=60)
|
|
57
|
+
)
|
|
58
|
+
async def fetch_data(
|
|
59
|
+
self, query_id: int, api_key: str, limit: int = 10
|
|
60
|
+
) -> Dict[str, Any]:
|
|
61
|
+
"""Fetch data for a specific Dune query.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
query_id: Dune query ID.
|
|
65
|
+
api_key: Dune API key.
|
|
66
|
+
limit: Maximum number of results (default 10).
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Dictionary of query results.
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
ToolException: If the API request fails.
|
|
73
|
+
"""
|
|
74
|
+
from langchain.tools.base import ToolException
|
|
75
|
+
|
|
76
|
+
url = f"{BASE_URL}/{query_id}/results?limit={limit}"
|
|
77
|
+
headers = {"X-Dune-API-Key": api_key}
|
|
78
|
+
|
|
79
|
+
async with httpx.AsyncClient() as client:
|
|
80
|
+
try:
|
|
81
|
+
response = await client.get(url, headers=headers, timeout=10)
|
|
82
|
+
response.raise_for_status()
|
|
83
|
+
return response.json().get("result", {})
|
|
84
|
+
except (httpx.RequestError, httpx.HTTPStatusError) as e:
|
|
85
|
+
raise ToolException(f"Error fetching data from Dune API: {e}")
|
|
86
|
+
|
|
87
|
+
async def _arun(
|
|
88
|
+
self,
|
|
89
|
+
limit: int = 10,
|
|
90
|
+
config: RunnableConfig = None,
|
|
91
|
+
**kwargs,
|
|
92
|
+
) -> str:
|
|
93
|
+
"""Fetch KOL memecoin buys asynchronously and return formatted output.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
limit: Maximum number of buy transactions to fetch (default 10).
|
|
97
|
+
config: Runnable configuration.
|
|
98
|
+
**kwargs: Additional keyword arguments.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Formatted string with KOL buy transactions or error message.
|
|
102
|
+
"""
|
|
103
|
+
import logging
|
|
104
|
+
|
|
105
|
+
logger = logging.getLogger(__name__)
|
|
106
|
+
context = self.context_from_config(config)
|
|
107
|
+
api_key = self.get_api_key(context)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
data = await self.fetch_data(KOL_BUYS_QUERY_ID, api_key, limit)
|
|
111
|
+
rows = data.get("rows", [])
|
|
112
|
+
if not rows:
|
|
113
|
+
return "No KOL buy transactions found."
|
|
114
|
+
|
|
115
|
+
output = f"Fetched {len(rows)} KOL memecoin buy transactions:\n"
|
|
116
|
+
for row in rows:
|
|
117
|
+
output += (
|
|
118
|
+
f"- {row['kol_with_link']} bought {row['token_with_chart']} "
|
|
119
|
+
f"(${row['amount_usd']:.2f}) at {row['buy_time']}\n"
|
|
120
|
+
)
|
|
121
|
+
return output.strip()
|
|
122
|
+
except Exception as e:
|
|
123
|
+
error_msg = f"Error fetching KOL memecoin buys: {str(e)}"
|
|
124
|
+
logger.warning(error_msg)
|
|
125
|
+
return error_msg
|
|
126
|
+
|
|
127
|
+
def _run(self, question: str):
|
|
128
|
+
raise NotImplementedError("Use _arun for async execution")
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Skill to fetch Crestal Nation metrics from Dune Analytics API.
|
|
2
|
+
|
|
3
|
+
Supports predefined metrics (e.g., total_users, unique_ai_citizens) or direct query IDs.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import difflib
|
|
7
|
+
import re
|
|
8
|
+
from typing import Any, Dict, Type
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
from langchain_core.runnables import RunnableConfig
|
|
12
|
+
from pydantic import BaseModel, Field
|
|
13
|
+
from tenacity import retry, stop_after_attempt, wait_exponential
|
|
14
|
+
|
|
15
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
16
|
+
from intentkit.skills.dune_analytics.base import DuneBaseTool
|
|
17
|
+
|
|
18
|
+
SUPPORTED_QUERIES = {
|
|
19
|
+
"total_users": 4858003,
|
|
20
|
+
"weekly_active_users": 4867200,
|
|
21
|
+
"unique_ai_citizens": 4857629,
|
|
22
|
+
"unique_creators": 4844506,
|
|
23
|
+
"ai_citizens_over_time": 4857629,
|
|
24
|
+
"chat_messages_over_time": 4857870,
|
|
25
|
+
"onchain_transactions": 4859895,
|
|
26
|
+
"total_chat_messages": 4857870,
|
|
27
|
+
"daily_skill_executions": 4861785,
|
|
28
|
+
"goods_services": 4859895,
|
|
29
|
+
"agent_tvl": 4859887,
|
|
30
|
+
"citizen_market_cap": 4859887,
|
|
31
|
+
}
|
|
32
|
+
QUERY_ALIASES = {
|
|
33
|
+
"agents": "unique_ai_citizens",
|
|
34
|
+
"citizens": "unique_ai_citizens",
|
|
35
|
+
"market_cap": "citizen_market_cap",
|
|
36
|
+
"nation_market_cap": "citizen_market_cap",
|
|
37
|
+
"number_of_agents": "unique_ai_citizens",
|
|
38
|
+
"number_of_citizens": "unique_ai_citizens",
|
|
39
|
+
"ai_citizens": "unique_ai_citizens",
|
|
40
|
+
"users": "total_users",
|
|
41
|
+
"active_users": "weekly_active_users",
|
|
42
|
+
"creators": "unique_creators",
|
|
43
|
+
"transactions": "onchain_transactions",
|
|
44
|
+
"messages": "total_chat_messages",
|
|
45
|
+
"skill_executions": "daily_skill_executions",
|
|
46
|
+
"tvl": "agent_tvl",
|
|
47
|
+
}
|
|
48
|
+
BASE_URL = "https://api.dune.com/api/v1/query"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class NationMetricsInput(BaseModel):
|
|
52
|
+
"""Input schema for fetching Crestal Nation metrics."""
|
|
53
|
+
|
|
54
|
+
metric: str = Field(
|
|
55
|
+
default="",
|
|
56
|
+
description="Metric name (e.g., total_users, agents) or query ID (e.g., 4858003). Empty for all configured metrics.",
|
|
57
|
+
)
|
|
58
|
+
limit: int = Field(
|
|
59
|
+
default=1000, description="Maximum number of results to fetch (default 1000)."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class MetricData(BaseModel):
|
|
64
|
+
"""Data model for a single metric result."""
|
|
65
|
+
|
|
66
|
+
metric: str = Field(description="Metric name or query ID")
|
|
67
|
+
data: Dict[str, Any] = Field(description="Metric data from Dune API")
|
|
68
|
+
error: str = Field(default="", description="Error message if fetch failed")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class NationMetricsOutput(BaseModel):
|
|
72
|
+
"""Output schema for Crestal Nation metrics."""
|
|
73
|
+
|
|
74
|
+
metrics: Dict[str, MetricData] = Field(
|
|
75
|
+
description="Dictionary of metric names or query IDs to their data"
|
|
76
|
+
)
|
|
77
|
+
summary: str = Field(description="Summary of fetched metrics")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class FetchNationMetrics(DuneBaseTool):
|
|
81
|
+
"""Skill to fetch Crestal Nation metrics from Dune Analytics API."""
|
|
82
|
+
|
|
83
|
+
name: str = "dune_fetch_nation_metrics"
|
|
84
|
+
description: str = (
|
|
85
|
+
"Fetches Crestal Nation metrics (e.g., total_users, agents/citizens, market_cap) from Dune Analytics API. "
|
|
86
|
+
"Supports predefined metrics, direct query IDs, or all configured metrics if none specified. "
|
|
87
|
+
"Handles rate limits with retries."
|
|
88
|
+
)
|
|
89
|
+
args_schema: Type[BaseModel] = NationMetricsInput
|
|
90
|
+
skill_store: SkillStoreABC = Field(description="Skill store for data persistence")
|
|
91
|
+
|
|
92
|
+
def normalize_metric(self, metric: str) -> str:
|
|
93
|
+
"""Normalize a metric string for matching.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
metric: Raw metric string from input.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Normalized metric string (lowercase, underscores, no punctuation).
|
|
100
|
+
"""
|
|
101
|
+
if not metric:
|
|
102
|
+
return ""
|
|
103
|
+
metric = re.sub(r"[^\w\s]", "", metric.lower()).replace(" ", "_")
|
|
104
|
+
return re.sub(r"_+", "_", metric).strip("_")
|
|
105
|
+
|
|
106
|
+
def find_closest_metrics(self, metric: str, max_suggestions: int = 3) -> list[str]:
|
|
107
|
+
"""Find the closest matching metrics using fuzzy matching.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
metric: Input metric to match against.
|
|
111
|
+
max_suggestions: Maximum number of suggestions to return.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
List of closest metric names.
|
|
115
|
+
"""
|
|
116
|
+
all_metrics = list(SUPPORTED_QUERIES.keys()) + list(QUERY_ALIASES.keys())
|
|
117
|
+
if not metric or not all_metrics:
|
|
118
|
+
return []
|
|
119
|
+
return difflib.get_close_matches(
|
|
120
|
+
metric, all_metrics, n=max_suggestions, cutoff=0.6
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
@retry(
|
|
124
|
+
stop=stop_after_attempt(3), wait=wait_exponential(multiplier=5, min=5, max=60)
|
|
125
|
+
)
|
|
126
|
+
async def fetch_data(
|
|
127
|
+
self, query_id: int, api_key: str, limit: int = 1000
|
|
128
|
+
) -> Dict[str, Any]:
|
|
129
|
+
"""Fetch data for a specific Dune query.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
query_id: Dune query ID.
|
|
133
|
+
api_key: Dune API key.
|
|
134
|
+
limit: Maximum number of results (default 1000).
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Dictionary of query results.
|
|
138
|
+
|
|
139
|
+
Raises:
|
|
140
|
+
ToolException: If the API request fails.
|
|
141
|
+
"""
|
|
142
|
+
from langchain.tools.base import ToolException
|
|
143
|
+
|
|
144
|
+
url = f"{BASE_URL}/{query_id}/results?limit={limit}"
|
|
145
|
+
headers = {"X-Dune-API-Key": api_key}
|
|
146
|
+
|
|
147
|
+
async with httpx.AsyncClient() as client:
|
|
148
|
+
try:
|
|
149
|
+
response = await client.get(url, headers=headers, timeout=10)
|
|
150
|
+
response.raise_for_status()
|
|
151
|
+
return response.json().get("result", {})
|
|
152
|
+
except (httpx.RequestError, httpx.HTTPStatusError) as e:
|
|
153
|
+
raise ToolException(f"Error fetching data from Dune API: {e}")
|
|
154
|
+
|
|
155
|
+
async def _arun(
|
|
156
|
+
self,
|
|
157
|
+
metric: str = "",
|
|
158
|
+
limit: int = 1000,
|
|
159
|
+
config: RunnableConfig = None,
|
|
160
|
+
**kwargs,
|
|
161
|
+
) -> NationMetricsOutput:
|
|
162
|
+
"""Fetch Crestal Nation metrics asynchronously.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
metric: Metric name (e.g., total_users) or query ID (e.g., 4858003). Empty for all configured metrics.
|
|
166
|
+
limit: Maximum number of results (default 1000).
|
|
167
|
+
config: Runnable configuration.
|
|
168
|
+
**kwargs: Additional keyword arguments.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
NationMetricsOutput with metric data and summary.
|
|
172
|
+
"""
|
|
173
|
+
import logging
|
|
174
|
+
|
|
175
|
+
logger = logging.getLogger(__name__)
|
|
176
|
+
context = self.context_from_config(config)
|
|
177
|
+
api_key = self.get_api_key(context)
|
|
178
|
+
|
|
179
|
+
metric = self.normalize_metric(metric)
|
|
180
|
+
metric = QUERY_ALIASES.get(metric, metric)
|
|
181
|
+
|
|
182
|
+
results = {}
|
|
183
|
+
metrics_to_fetch = {}
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
query_id = int(metric)
|
|
187
|
+
metrics_to_fetch[str(query_id)] = query_id
|
|
188
|
+
except (ValueError, TypeError):
|
|
189
|
+
metrics_to_fetch = (
|
|
190
|
+
SUPPORTED_QUERIES
|
|
191
|
+
if not metric
|
|
192
|
+
else (
|
|
193
|
+
{metric: SUPPORTED_QUERIES[metric]}
|
|
194
|
+
if metric in SUPPORTED_QUERIES
|
|
195
|
+
else {}
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
if not metrics_to_fetch:
|
|
200
|
+
closest_metrics = self.find_closest_metrics(metric)
|
|
201
|
+
supported = ", ".join(SUPPORTED_QUERIES.keys())
|
|
202
|
+
suggestions = (
|
|
203
|
+
f" Did you mean: {', '.join(closest_metrics)}?"
|
|
204
|
+
if closest_metrics
|
|
205
|
+
else ""
|
|
206
|
+
)
|
|
207
|
+
logger.warning(
|
|
208
|
+
"Unrecognized metric or query ID: %s. Suggested: %s",
|
|
209
|
+
metric,
|
|
210
|
+
closest_metrics,
|
|
211
|
+
)
|
|
212
|
+
return NationMetricsOutput(
|
|
213
|
+
metrics={},
|
|
214
|
+
summary=(
|
|
215
|
+
f"Invalid metric or query ID: {metric}. Supported metrics include: {supported}.{suggestions} "
|
|
216
|
+
"Try 'fetch nation metrics total_users' or a valid query ID, or submit a feature request at "
|
|
217
|
+
"https://github.com/crestalnetwork/intentkit."
|
|
218
|
+
),
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
for metric_name, query_id in metrics_to_fetch.items():
|
|
222
|
+
try:
|
|
223
|
+
data = await self.fetch_data(query_id, api_key, limit)
|
|
224
|
+
results[metric_name] = MetricData(metric=metric_name, data=data)
|
|
225
|
+
except Exception as e:
|
|
226
|
+
results[metric_name] = MetricData(
|
|
227
|
+
metric=metric_name, data={}, error=str(e)
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
summary = f"Fetched data for {len([m for m in results.values() if not m.error])}/{len(metrics_to_fetch)} metrics."
|
|
231
|
+
if any(m.error for m in results.values()):
|
|
232
|
+
summary += f" Errors occurred for: {', '.join(m.metric for m in results.values() if m.error)}."
|
|
233
|
+
|
|
234
|
+
return NationMetricsOutput(metrics=results, summary=summary)
|
|
235
|
+
|
|
236
|
+
def _run(self, question: str):
|
|
237
|
+
raise NotImplementedError("Use _arun for async execution")
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Dune Analytics",
|
|
3
|
+
"description": "Dune Analytics skills to fetch data from Dune Analytics API.",
|
|
4
|
+
"x-icon": "https://ai.service.crestal.dev/skills/dune_analytics/dune.png",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"enabled": {
|
|
8
|
+
"type": "boolean",
|
|
9
|
+
"title": "Enabled",
|
|
10
|
+
"description": "Whether this skill is enabled",
|
|
11
|
+
"default": false
|
|
12
|
+
},
|
|
13
|
+
"states": {
|
|
14
|
+
"title": "Skill States",
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"fetch_nation_metrics": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"title": "Fetch Crestal Nation Metrics",
|
|
20
|
+
"enum": [
|
|
21
|
+
"disabled",
|
|
22
|
+
"public",
|
|
23
|
+
"private"
|
|
24
|
+
],
|
|
25
|
+
"x-enum-title": [
|
|
26
|
+
"Disabled",
|
|
27
|
+
"Agent Owner + All Users",
|
|
28
|
+
"Agent Owner Only"
|
|
29
|
+
],
|
|
30
|
+
"description": "Fetches Crestal Nation metrics (e.g., total_users, agents/citizens, market_cap) from Dune Analytics API.",
|
|
31
|
+
"default": "disabled"
|
|
32
|
+
},
|
|
33
|
+
"fetch_kol_buys": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"title": "Fetch KOL Memecoin Buys",
|
|
36
|
+
"enum": [
|
|
37
|
+
"disabled",
|
|
38
|
+
"public",
|
|
39
|
+
"private"
|
|
40
|
+
],
|
|
41
|
+
"x-enum-title": [
|
|
42
|
+
"Disabled",
|
|
43
|
+
"Agent Owner + All Users",
|
|
44
|
+
"Agent Owner Only"
|
|
45
|
+
],
|
|
46
|
+
"description": "Fetches a list of KOL memecoin buy transactions on Solana from Dune Analytics API.",
|
|
47
|
+
"default": "disabled"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"api_key_provider": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"title": "API Key Provider",
|
|
54
|
+
"description": "Provider of the API key for Dune service",
|
|
55
|
+
"enum": [
|
|
56
|
+
"agent_owner"
|
|
57
|
+
],
|
|
58
|
+
"x-enum-title": [
|
|
59
|
+
"Owner Provided"
|
|
60
|
+
],
|
|
61
|
+
"default": "agent_owner"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"required": [
|
|
65
|
+
"states",
|
|
66
|
+
"enabled"
|
|
67
|
+
],
|
|
68
|
+
"if": {
|
|
69
|
+
"properties": {
|
|
70
|
+
"api_key_provider": {
|
|
71
|
+
"const": "agent_owner"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"then": {
|
|
76
|
+
"properties": {
|
|
77
|
+
"api_key": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"title": "Dune API Key",
|
|
80
|
+
"description": "API key for Dune Analytics (X-Dune-API-Key).",
|
|
81
|
+
"x-link": "[Get your API key](https://docs.dune.com/api-reference/overview/authentication)",
|
|
82
|
+
"x-sensitive": true
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"if": {
|
|
86
|
+
"properties": {
|
|
87
|
+
"enabled": {
|
|
88
|
+
"const": true
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"then": {
|
|
93
|
+
"required": [
|
|
94
|
+
"api_key"
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"additionalProperties": true
|
|
99
|
+
}
|