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,135 @@
|
|
|
1
|
+
"""Base class for all DeFi Llama tools."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from typing import Type
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.abstracts.skill import SkillStoreABC
|
|
9
|
+
from intentkit.skills.base import IntentKitSkill, SkillContext
|
|
10
|
+
from intentkit.skills.defillama.config.chains import (
|
|
11
|
+
get_chain_from_alias,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
DEFILLAMA_BASE_URL = "https://api.llama.fi"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DefiLlamaBaseTool(IntentKitSkill):
|
|
18
|
+
"""Base class for DeFi Llama tools.
|
|
19
|
+
|
|
20
|
+
This class provides common functionality for all DeFi Llama API tools:
|
|
21
|
+
- Rate limiting
|
|
22
|
+
- State management
|
|
23
|
+
- Chain validation
|
|
24
|
+
- Error handling
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
name: str = Field(description="The name of the tool")
|
|
28
|
+
description: str = Field(description="A description of what the tool does")
|
|
29
|
+
args_schema: Type[BaseModel]
|
|
30
|
+
skill_store: SkillStoreABC = Field(
|
|
31
|
+
description="The skill store for persisting data"
|
|
32
|
+
)
|
|
33
|
+
base_url: str = Field(
|
|
34
|
+
default=DEFILLAMA_BASE_URL, description="Base URL for DeFi Llama API"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def category(self) -> str:
|
|
39
|
+
return "defillama"
|
|
40
|
+
|
|
41
|
+
async def check_rate_limit(
|
|
42
|
+
self, context: SkillContext, max_requests: int = 30, interval: int = 5
|
|
43
|
+
) -> tuple[bool, str | None]:
|
|
44
|
+
"""Check if the rate limit has been exceeded.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
context: Skill context
|
|
48
|
+
max_requests: Maximum requests allowed in the interval (default: 30)
|
|
49
|
+
interval: Time interval in minutes (default: 5)
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Rate limit status and error message if limited
|
|
53
|
+
"""
|
|
54
|
+
rate_limit = await self.skill_store.get_agent_skill_data(
|
|
55
|
+
context.agent.id, self.name, "rate_limit"
|
|
56
|
+
)
|
|
57
|
+
current_time = datetime.now(tz=timezone.utc)
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
rate_limit
|
|
61
|
+
and rate_limit.get("reset_time")
|
|
62
|
+
and rate_limit.get("count") is not None
|
|
63
|
+
and datetime.fromisoformat(rate_limit["reset_time"]) > current_time
|
|
64
|
+
):
|
|
65
|
+
if rate_limit["count"] >= max_requests:
|
|
66
|
+
return True, "Rate limit exceeded"
|
|
67
|
+
|
|
68
|
+
rate_limit["count"] += 1
|
|
69
|
+
await self.skill_store.save_agent_skill_data(
|
|
70
|
+
context.agent.id, self.name, "rate_limit", rate_limit
|
|
71
|
+
)
|
|
72
|
+
return False, None
|
|
73
|
+
|
|
74
|
+
new_rate_limit = {
|
|
75
|
+
"count": 1,
|
|
76
|
+
"reset_time": (current_time + timedelta(minutes=interval)).isoformat(),
|
|
77
|
+
}
|
|
78
|
+
await self.skill_store.save_agent_skill_data(
|
|
79
|
+
context.agent.id, self.name, "rate_limit", new_rate_limit
|
|
80
|
+
)
|
|
81
|
+
return False, None
|
|
82
|
+
|
|
83
|
+
async def validate_chain(self, chain: str | None) -> tuple[bool, str | None]:
|
|
84
|
+
"""Validate and normalize chain parameter.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
chain: Chain name to validate
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Tuple of (is_valid, normalized_chain_name)
|
|
91
|
+
"""
|
|
92
|
+
if chain is None:
|
|
93
|
+
return True, None
|
|
94
|
+
|
|
95
|
+
normalized_chain = get_chain_from_alias(chain)
|
|
96
|
+
if normalized_chain is None:
|
|
97
|
+
return False, None
|
|
98
|
+
|
|
99
|
+
return True, normalized_chain
|
|
100
|
+
|
|
101
|
+
def get_endpoint_url(self, endpoint: str) -> str:
|
|
102
|
+
"""Construct full endpoint URL.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
endpoint: API endpoint path
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Complete URL for the endpoint
|
|
109
|
+
"""
|
|
110
|
+
return f"{self.base_url}/{endpoint.lstrip('/')}"
|
|
111
|
+
|
|
112
|
+
def format_error_response(self, status_code: int, message: str) -> dict:
|
|
113
|
+
"""Format error responses consistently.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
status_code: HTTP status code
|
|
117
|
+
message: Error message
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Formatted error response dictionary
|
|
121
|
+
"""
|
|
122
|
+
return {
|
|
123
|
+
"error": True,
|
|
124
|
+
"status_code": status_code,
|
|
125
|
+
"message": message,
|
|
126
|
+
"timestamp": datetime.now(tz=timezone.utc).isoformat(),
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
def get_current_timestamp(self) -> int:
|
|
130
|
+
"""Get current timestamp in UTC.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Current Unix timestamp
|
|
134
|
+
"""
|
|
135
|
+
return int(datetime.now(tz=timezone.utc).timestamp())
|
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Tool for fetching batch historical token prices via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional, Type
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_batch_historical_prices
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_BATCH_HISTORICAL_PRICES_PROMPT = """
|
|
12
|
+
This tool fetches historical token prices from DeFi Llama for multiple tokens at multiple timestamps.
|
|
13
|
+
Provide a dictionary mapping token identifiers to lists of timestamps in the format:
|
|
14
|
+
- Ethereum tokens: {"ethereum:0x...": [timestamp1, timestamp2]}
|
|
15
|
+
- Other chains: {"chainname:0x...": [timestamp1, timestamp2]}
|
|
16
|
+
- CoinGecko IDs: {"coingecko:bitcoin": [timestamp1, timestamp2]}
|
|
17
|
+
Returns historical price data including:
|
|
18
|
+
- Prices in USD at each timestamp
|
|
19
|
+
- Token symbols
|
|
20
|
+
- Confidence scores for price data
|
|
21
|
+
Uses a 4-hour search window around each specified timestamp.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class HistoricalPricePoint(BaseModel):
|
|
26
|
+
"""Model representing a single historical price point."""
|
|
27
|
+
|
|
28
|
+
timestamp: int = Field(..., description="Unix timestamp of the price data")
|
|
29
|
+
price: float = Field(..., description="Token price in USD at the timestamp")
|
|
30
|
+
confidence: float = Field(..., description="Confidence score for the price data")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TokenPriceHistory(BaseModel):
|
|
34
|
+
"""Model representing historical price data for a single token."""
|
|
35
|
+
|
|
36
|
+
symbol: str = Field(..., description="Token symbol")
|
|
37
|
+
prices: List[HistoricalPricePoint] = Field(
|
|
38
|
+
..., description="List of historical price points"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class FetchBatchHistoricalPricesInput(BaseModel):
|
|
43
|
+
"""Input schema for fetching batch historical token prices."""
|
|
44
|
+
|
|
45
|
+
coins_timestamps: Dict[str, List[int]] = Field(
|
|
46
|
+
..., description="Dictionary mapping token identifiers to lists of timestamps"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class FetchBatchHistoricalPricesResponse(BaseModel):
|
|
51
|
+
"""Response schema for batch historical token prices."""
|
|
52
|
+
|
|
53
|
+
coins: Dict[str, TokenPriceHistory] = Field(
|
|
54
|
+
default_factory=dict,
|
|
55
|
+
description="Historical token prices keyed by token identifier",
|
|
56
|
+
)
|
|
57
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class DefiLlamaFetchBatchHistoricalPrices(DefiLlamaBaseTool):
|
|
61
|
+
"""Tool for fetching batch historical token prices from DeFi Llama.
|
|
62
|
+
|
|
63
|
+
This tool retrieves historical prices for multiple tokens at multiple
|
|
64
|
+
timestamps, using a 4-hour search window around each requested time.
|
|
65
|
+
|
|
66
|
+
Example:
|
|
67
|
+
prices_tool = DefiLlamaFetchBatchHistoricalPrices(
|
|
68
|
+
skill_store=store,
|
|
69
|
+
agent_id="agent_123",
|
|
70
|
+
agent_store=agent_store
|
|
71
|
+
)
|
|
72
|
+
result = await prices_tool._arun(
|
|
73
|
+
coins_timestamps={
|
|
74
|
+
"ethereum:0x...": [1640995200, 1641081600], # Jan 1-2, 2022
|
|
75
|
+
"coingecko:bitcoin": [1640995200, 1641081600]
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
name: str = "defillama_fetch_batch_historical_prices"
|
|
81
|
+
description: str = FETCH_BATCH_HISTORICAL_PRICES_PROMPT
|
|
82
|
+
args_schema: Type[BaseModel] = FetchBatchHistoricalPricesInput
|
|
83
|
+
|
|
84
|
+
async def _arun(
|
|
85
|
+
self, config: RunnableConfig, coins_timestamps: Dict[str, List[int]]
|
|
86
|
+
) -> FetchBatchHistoricalPricesResponse:
|
|
87
|
+
"""Fetch historical prices for the given tokens at specified timestamps.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
config: Runnable configuration
|
|
91
|
+
coins_timestamps: Dictionary mapping token identifiers to lists of timestamps
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
FetchBatchHistoricalPricesResponse containing historical token prices or error
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
# Check rate limiting
|
|
98
|
+
context = self.context_from_config(config)
|
|
99
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
100
|
+
if is_rate_limited:
|
|
101
|
+
return FetchBatchHistoricalPricesResponse(error=error_msg)
|
|
102
|
+
|
|
103
|
+
# Fetch batch historical prices from API
|
|
104
|
+
result = await fetch_batch_historical_prices(
|
|
105
|
+
coins_timestamps=coins_timestamps
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Check for API errors
|
|
109
|
+
if isinstance(result, dict) and "error" in result:
|
|
110
|
+
return FetchBatchHistoricalPricesResponse(error=result["error"])
|
|
111
|
+
|
|
112
|
+
# Return the response matching the API structure
|
|
113
|
+
return FetchBatchHistoricalPricesResponse(coins=result["coins"])
|
|
114
|
+
|
|
115
|
+
except Exception as e:
|
|
116
|
+
return FetchBatchHistoricalPricesResponse(error=str(e))
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Tool for fetching current block data via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Type
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_block
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_BLOCK_PROMPT = """
|
|
12
|
+
This tool fetches current block data from DeFi Llama for a specific chain.
|
|
13
|
+
Provide:
|
|
14
|
+
- Chain name (e.g. "ethereum", "bsc", "solana")
|
|
15
|
+
Returns:
|
|
16
|
+
- Block height
|
|
17
|
+
- Block timestamp
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BlockData(BaseModel):
|
|
22
|
+
"""Model representing block data."""
|
|
23
|
+
|
|
24
|
+
height: int = Field(..., description="Block height number")
|
|
25
|
+
timestamp: int = Field(..., description="Unix timestamp of the block")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class FetchBlockInput(BaseModel):
|
|
29
|
+
"""Input schema for fetching block data."""
|
|
30
|
+
|
|
31
|
+
chain: str = Field(..., description="Chain name to fetch block data for")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class FetchBlockResponse(BaseModel):
|
|
35
|
+
"""Response schema for block data."""
|
|
36
|
+
|
|
37
|
+
chain: str = Field(..., description="Normalized chain name")
|
|
38
|
+
height: Optional[int] = Field(None, description="Block height number")
|
|
39
|
+
timestamp: Optional[int] = Field(None, description="Unix timestamp of the block")
|
|
40
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class DefiLlamaFetchBlock(DefiLlamaBaseTool):
|
|
44
|
+
"""Tool for fetching current block data from DeFi Llama.
|
|
45
|
+
|
|
46
|
+
This tool retrieves current block data for a specific chain.
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
block_tool = DefiLlamaFetchBlock(
|
|
50
|
+
skill_store=store,
|
|
51
|
+
agent_id="agent_123",
|
|
52
|
+
agent_store=agent_store
|
|
53
|
+
)
|
|
54
|
+
result = await block_tool._arun(chain="ethereum")
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
name: str = "defillama_fetch_block"
|
|
58
|
+
description: str = FETCH_BLOCK_PROMPT
|
|
59
|
+
args_schema: Type[BaseModel] = FetchBlockInput
|
|
60
|
+
|
|
61
|
+
async def _arun(self, config: RunnableConfig, chain: str) -> FetchBlockResponse:
|
|
62
|
+
"""Fetch current block data for the given chain.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
config: Runnable configuration
|
|
66
|
+
chain: Chain name to fetch block data for
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
FetchBlockResponse containing block data or error
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
# Validate chain parameter
|
|
73
|
+
is_valid, normalized_chain = await self.validate_chain(chain)
|
|
74
|
+
if not is_valid or normalized_chain is None:
|
|
75
|
+
return FetchBlockResponse(chain=chain, error=f"Invalid chain: {chain}")
|
|
76
|
+
|
|
77
|
+
# Check rate limiting
|
|
78
|
+
context = self.context_from_config(config)
|
|
79
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
80
|
+
if is_rate_limited:
|
|
81
|
+
return FetchBlockResponse(chain=normalized_chain, error=error_msg)
|
|
82
|
+
|
|
83
|
+
# Fetch block data from API
|
|
84
|
+
result = await fetch_block(chain=normalized_chain)
|
|
85
|
+
|
|
86
|
+
# Check for API errors
|
|
87
|
+
if isinstance(result, dict) and "error" in result:
|
|
88
|
+
return FetchBlockResponse(chain=normalized_chain, error=result["error"])
|
|
89
|
+
|
|
90
|
+
# Return the response matching the API structure
|
|
91
|
+
return FetchBlockResponse(
|
|
92
|
+
chain=normalized_chain,
|
|
93
|
+
height=result["height"],
|
|
94
|
+
timestamp=result["timestamp"],
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
except Exception as e:
|
|
98
|
+
return FetchBlockResponse(chain=chain, error=str(e))
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Tool for fetching token prices via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional, Type
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_current_prices
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_PRICES_PROMPT = """
|
|
12
|
+
This tool fetches current token prices from DeFi Llama with a 4-hour search window.
|
|
13
|
+
Provide a list of token identifiers in the format:
|
|
14
|
+
- Ethereum tokens: 'ethereum:0x...'
|
|
15
|
+
- Other chains: 'chainname:0x...'
|
|
16
|
+
- CoinGecko IDs: 'coingecko:bitcoin'
|
|
17
|
+
Returns price data including:
|
|
18
|
+
- Current price in USD
|
|
19
|
+
- Token symbol
|
|
20
|
+
- Price confidence score
|
|
21
|
+
- Token decimals (if available)
|
|
22
|
+
- Last update timestamp
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TokenPrice(BaseModel):
|
|
27
|
+
"""Model representing token price data."""
|
|
28
|
+
|
|
29
|
+
price: float = Field(..., description="Current token price in USD")
|
|
30
|
+
symbol: str = Field(..., description="Token symbol")
|
|
31
|
+
timestamp: int = Field(..., description="Unix timestamp of last price update")
|
|
32
|
+
confidence: float = Field(..., description="Confidence score for the price data")
|
|
33
|
+
decimals: Optional[int] = Field(None, description="Token decimals, if available")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FetchCurrentPricesInput(BaseModel):
|
|
37
|
+
"""Input schema for fetching current token prices with a 4-hour search window."""
|
|
38
|
+
|
|
39
|
+
coins: List[str] = Field(
|
|
40
|
+
...,
|
|
41
|
+
description="List of token identifiers (e.g. 'ethereum:0x...', 'coingecko:ethereum')",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class FetchCurrentPricesResponse(BaseModel):
|
|
46
|
+
"""Response schema for current token prices."""
|
|
47
|
+
|
|
48
|
+
coins: Dict[str, TokenPrice] = Field(
|
|
49
|
+
default_factory=dict, description="Token prices keyed by token identifier"
|
|
50
|
+
)
|
|
51
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DefiLlamaFetchCurrentPrices(DefiLlamaBaseTool):
|
|
55
|
+
"""Tool for fetching current token prices from DeFi Llama.
|
|
56
|
+
|
|
57
|
+
This tool retrieves current prices for multiple tokens in a single request,
|
|
58
|
+
using a 4-hour search window to ensure fresh data.
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
prices_tool = DefiLlamaFetchCurrentPrices(
|
|
62
|
+
skill_store=store,
|
|
63
|
+
agent_id="agent_123",
|
|
64
|
+
agent_store=agent_store
|
|
65
|
+
)
|
|
66
|
+
result = await prices_tool._arun(
|
|
67
|
+
coins=["ethereum:0x...", "coingecko:bitcoin"]
|
|
68
|
+
)
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
name: str = "defillama_fetch_current_prices"
|
|
72
|
+
description: str = FETCH_PRICES_PROMPT
|
|
73
|
+
args_schema: Type[BaseModel] = FetchCurrentPricesInput
|
|
74
|
+
|
|
75
|
+
async def _arun(
|
|
76
|
+
self, config: RunnableConfig, coins: List[str]
|
|
77
|
+
) -> FetchCurrentPricesResponse:
|
|
78
|
+
"""Fetch current prices for the given tokens.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
config: Runnable configuration
|
|
82
|
+
coins: List of token identifiers to fetch prices for
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
FetchCurrentPricesResponse containing token prices or error
|
|
86
|
+
"""
|
|
87
|
+
try:
|
|
88
|
+
# Check rate limiting
|
|
89
|
+
context = self.context_from_config(config)
|
|
90
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
91
|
+
if is_rate_limited:
|
|
92
|
+
return FetchCurrentPricesResponse(error=error_msg)
|
|
93
|
+
|
|
94
|
+
# Fetch prices from API
|
|
95
|
+
result = await fetch_current_prices(coins=coins)
|
|
96
|
+
|
|
97
|
+
# Check for API errors
|
|
98
|
+
if isinstance(result, dict) and "error" in result:
|
|
99
|
+
return FetchCurrentPricesResponse(error=result["error"])
|
|
100
|
+
|
|
101
|
+
# Return the response matching the API structure
|
|
102
|
+
return FetchCurrentPricesResponse(coins=result["coins"])
|
|
103
|
+
|
|
104
|
+
except Exception as e:
|
|
105
|
+
return FetchCurrentPricesResponse(error=str(e))
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Tool for fetching first recorded token prices via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional, Type
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_first_price
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_FIRST_PRICE_PROMPT = """
|
|
12
|
+
This tool fetches the first recorded price data from DeFi Llama for multiple tokens.
|
|
13
|
+
Provide a list of token identifiers in the format:
|
|
14
|
+
- Ethereum tokens: 'ethereum:0x...'
|
|
15
|
+
- Other chains: 'chainname:0x...'
|
|
16
|
+
- CoinGecko IDs: 'coingecko:bitcoin'
|
|
17
|
+
Returns first price data including:
|
|
18
|
+
- Initial price in USD
|
|
19
|
+
- Token symbol
|
|
20
|
+
- Timestamp of first recorded price
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class FirstPriceData(BaseModel):
|
|
25
|
+
"""Model representing first price data for a single token."""
|
|
26
|
+
|
|
27
|
+
symbol: str = Field(..., description="Token symbol")
|
|
28
|
+
price: float = Field(..., description="First recorded price in USD")
|
|
29
|
+
timestamp: int = Field(..., description="Unix timestamp of first recorded price")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class FetchFirstPriceInput(BaseModel):
|
|
33
|
+
"""Input schema for fetching first token prices."""
|
|
34
|
+
|
|
35
|
+
coins: List[str] = Field(
|
|
36
|
+
..., description="List of token identifiers to fetch first prices for"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class FetchFirstPriceResponse(BaseModel):
|
|
41
|
+
"""Response schema for first token prices."""
|
|
42
|
+
|
|
43
|
+
coins: Dict[str, FirstPriceData] = Field(
|
|
44
|
+
default_factory=dict, description="First price data keyed by token identifier"
|
|
45
|
+
)
|
|
46
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class DefiLlamaFetchFirstPrice(DefiLlamaBaseTool):
|
|
50
|
+
"""Tool for fetching first recorded token prices from DeFi Llama.
|
|
51
|
+
|
|
52
|
+
This tool retrieves the first price data recorded for multiple tokens,
|
|
53
|
+
including the initial price, symbol, and timestamp.
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
first_price_tool = DefiLlamaFetchFirstPrice(
|
|
57
|
+
skill_store=store,
|
|
58
|
+
agent_id="agent_123",
|
|
59
|
+
agent_store=agent_store
|
|
60
|
+
)
|
|
61
|
+
result = await first_price_tool._arun(
|
|
62
|
+
coins=["ethereum:0x...", "coingecko:ethereum"]
|
|
63
|
+
)
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
name: str = "defillama_fetch_first_price"
|
|
67
|
+
description: str = FETCH_FIRST_PRICE_PROMPT
|
|
68
|
+
args_schema: Type[BaseModel] = FetchFirstPriceInput
|
|
69
|
+
|
|
70
|
+
async def _arun(
|
|
71
|
+
self, config: RunnableConfig, coins: List[str]
|
|
72
|
+
) -> FetchFirstPriceResponse:
|
|
73
|
+
"""Fetch first recorded prices for the given tokens.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
config: Runnable configuration
|
|
77
|
+
coins: List of token identifiers to fetch first prices for
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
FetchFirstPriceResponse containing first price data or error
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
# Check rate limiting
|
|
84
|
+
context = self.context_from_config(config)
|
|
85
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
86
|
+
if is_rate_limited:
|
|
87
|
+
return FetchFirstPriceResponse(error=error_msg)
|
|
88
|
+
|
|
89
|
+
# Fetch first price data from API
|
|
90
|
+
result = await fetch_first_price(coins=coins)
|
|
91
|
+
|
|
92
|
+
# Check for API errors
|
|
93
|
+
if isinstance(result, dict) and "error" in result:
|
|
94
|
+
return FetchFirstPriceResponse(error=result["error"])
|
|
95
|
+
|
|
96
|
+
# Return the response matching the API structure
|
|
97
|
+
return FetchFirstPriceResponse(coins=result["coins"])
|
|
98
|
+
|
|
99
|
+
except Exception as e:
|
|
100
|
+
return FetchFirstPriceResponse(error=str(e))
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Tool for fetching historical token prices via DeFi Llama API."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional, Type
|
|
4
|
+
|
|
5
|
+
from langchain.schema.runnable import RunnableConfig
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from intentkit.skills.defillama.api import fetch_historical_prices
|
|
9
|
+
from intentkit.skills.defillama.base import DefiLlamaBaseTool
|
|
10
|
+
|
|
11
|
+
FETCH_HISTORICAL_PRICES_PROMPT = """
|
|
12
|
+
This tool fetches historical token prices from DeFi Llama for a specific timestamp.
|
|
13
|
+
Provide a timestamp and list of token identifiers in the format:
|
|
14
|
+
- Ethereum tokens: 'ethereum:0x...'
|
|
15
|
+
- Other chains: 'chainname:0x...'
|
|
16
|
+
- CoinGecko IDs: 'coingecko:bitcoin'
|
|
17
|
+
Returns historical price data including:
|
|
18
|
+
- Price in USD at the specified time
|
|
19
|
+
- Token symbol
|
|
20
|
+
- Token decimals (if available)
|
|
21
|
+
- Actual timestamp of the price data
|
|
22
|
+
Uses a 4-hour search window around the specified timestamp.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class HistoricalTokenPrice(BaseModel):
|
|
27
|
+
"""Model representing historical token price data."""
|
|
28
|
+
|
|
29
|
+
price: float = Field(..., description="Token price in USD at the specified time")
|
|
30
|
+
symbol: Optional[str] = Field(None, description="Token symbol")
|
|
31
|
+
timestamp: int = Field(..., description="Unix timestamp of the price data")
|
|
32
|
+
decimals: Optional[int] = Field(None, description="Token decimals, if available")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class FetchHistoricalPricesInput(BaseModel):
|
|
36
|
+
"""Input schema for fetching historical token prices."""
|
|
37
|
+
|
|
38
|
+
timestamp: int = Field(
|
|
39
|
+
..., description="Unix timestamp for historical price lookup"
|
|
40
|
+
)
|
|
41
|
+
coins: List[str] = Field(
|
|
42
|
+
...,
|
|
43
|
+
description="List of token identifiers (e.g. 'ethereum:0x...', 'coingecko:ethereum')",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class FetchHistoricalPricesResponse(BaseModel):
|
|
48
|
+
"""Response schema for historical token prices."""
|
|
49
|
+
|
|
50
|
+
coins: Dict[str, HistoricalTokenPrice] = Field(
|
|
51
|
+
default_factory=dict,
|
|
52
|
+
description="Historical token prices keyed by token identifier",
|
|
53
|
+
)
|
|
54
|
+
error: Optional[str] = Field(None, description="Error message if any")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class DefiLlamaFetchHistoricalPrices(DefiLlamaBaseTool):
|
|
58
|
+
"""Tool for fetching historical token prices from DeFi Llama.
|
|
59
|
+
|
|
60
|
+
This tool retrieves historical prices for multiple tokens at a specific
|
|
61
|
+
timestamp, using a 4-hour search window around the requested time.
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
prices_tool = DefiLlamaFetchHistoricalPrices(
|
|
65
|
+
skill_store=store,
|
|
66
|
+
agent_id="agent_123",
|
|
67
|
+
agent_store=agent_store
|
|
68
|
+
)
|
|
69
|
+
result = await prices_tool._arun(
|
|
70
|
+
timestamp=1640995200, # Jan 1, 2022
|
|
71
|
+
coins=["ethereum:0x...", "coingecko:bitcoin"]
|
|
72
|
+
)
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
name: str = "defillama_fetch_historical_prices"
|
|
76
|
+
description: str = FETCH_HISTORICAL_PRICES_PROMPT
|
|
77
|
+
args_schema: Type[BaseModel] = FetchHistoricalPricesInput
|
|
78
|
+
|
|
79
|
+
async def _arun(
|
|
80
|
+
self, config: RunnableConfig, timestamp: int, coins: List[str]
|
|
81
|
+
) -> FetchHistoricalPricesResponse:
|
|
82
|
+
"""Fetch historical prices for the given tokens at the specified time.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
config: Runnable configuration
|
|
86
|
+
timestamp: Unix timestamp for historical price lookup
|
|
87
|
+
coins: List of token identifiers to fetch prices for
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
FetchHistoricalPricesResponse containing historical token prices or error
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
# Check rate limiting
|
|
94
|
+
context = self.context_from_config(config)
|
|
95
|
+
is_rate_limited, error_msg = await self.check_rate_limit(context)
|
|
96
|
+
if is_rate_limited:
|
|
97
|
+
return FetchHistoricalPricesResponse(error=error_msg)
|
|
98
|
+
|
|
99
|
+
# Fetch historical prices from API
|
|
100
|
+
result = await fetch_historical_prices(timestamp=timestamp, coins=coins)
|
|
101
|
+
|
|
102
|
+
# Check for API errors
|
|
103
|
+
if isinstance(result, dict) and "error" in result:
|
|
104
|
+
return FetchHistoricalPricesResponse(error=result["error"])
|
|
105
|
+
|
|
106
|
+
# Return the response matching the API structure
|
|
107
|
+
return FetchHistoricalPricesResponse(coins=result["coins"])
|
|
108
|
+
|
|
109
|
+
except Exception as e:
|
|
110
|
+
return FetchHistoricalPricesResponse(error=str(e))
|