intentkit 0.7.5.dev3__py3-none-any.whl → 0.8.34.dev7__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.
- intentkit/MANIFEST.in +14 -0
- intentkit/README.md +88 -0
- intentkit/__init__.py +6 -4
- intentkit/abstracts/agent.py +4 -5
- intentkit/abstracts/engine.py +5 -5
- intentkit/abstracts/graph.py +15 -8
- intentkit/abstracts/skill.py +6 -144
- intentkit/abstracts/twitter.py +4 -5
- intentkit/clients/__init__.py +9 -2
- intentkit/clients/cdp.py +129 -153
- intentkit/{utils → clients}/s3.py +109 -34
- intentkit/clients/twitter.py +83 -62
- intentkit/clients/web3.py +4 -7
- intentkit/config/config.py +123 -90
- intentkit/core/account_checking.py +802 -0
- intentkit/core/agent.py +313 -498
- intentkit/core/asset.py +267 -0
- intentkit/core/chat.py +5 -3
- intentkit/core/client.py +1 -1
- intentkit/core/credit.py +49 -41
- intentkit/core/draft.py +201 -0
- intentkit/core/draft_chat.py +118 -0
- intentkit/core/engine.py +378 -287
- intentkit/core/manager/__init__.py +25 -0
- intentkit/core/manager/engine.py +220 -0
- intentkit/core/manager/service.py +172 -0
- intentkit/core/manager/skills.py +178 -0
- intentkit/core/middleware.py +231 -0
- intentkit/core/prompt.py +74 -114
- intentkit/core/scheduler.py +143 -0
- intentkit/core/statistics.py +168 -0
- intentkit/models/agent.py +931 -518
- intentkit/models/agent_data.py +165 -106
- intentkit/models/agent_schema.json +38 -251
- intentkit/models/app_setting.py +15 -13
- intentkit/models/chat.py +86 -140
- intentkit/models/credit.py +182 -162
- intentkit/models/db.py +42 -23
- intentkit/models/db_mig.py +120 -3
- intentkit/models/draft.py +222 -0
- intentkit/models/llm.csv +31 -0
- intentkit/models/llm.py +262 -370
- intentkit/models/redis.py +6 -4
- intentkit/models/skill.py +222 -101
- intentkit/models/skills.csv +173 -0
- intentkit/models/team.py +189 -0
- intentkit/models/user.py +103 -31
- intentkit/skills/acolyt/__init__.py +2 -9
- intentkit/skills/acolyt/ask.py +3 -4
- intentkit/skills/acolyt/base.py +4 -9
- intentkit/skills/acolyt/schema.json +4 -3
- intentkit/skills/aixbt/__init__.py +2 -13
- intentkit/skills/aixbt/base.py +1 -7
- intentkit/skills/aixbt/projects.py +14 -15
- intentkit/skills/aixbt/schema.json +4 -4
- intentkit/skills/allora/__init__.py +2 -9
- intentkit/skills/allora/base.py +4 -9
- intentkit/skills/allora/price.py +3 -4
- intentkit/skills/allora/schema.json +3 -2
- intentkit/skills/base.py +241 -41
- intentkit/skills/basename/__init__.py +51 -0
- intentkit/skills/basename/base.py +11 -0
- intentkit/skills/basename/basename.svg +11 -0
- intentkit/skills/basename/schema.json +58 -0
- intentkit/skills/carv/__init__.py +115 -121
- intentkit/skills/carv/base.py +184 -185
- intentkit/skills/carv/fetch_news.py +3 -3
- intentkit/skills/carv/onchain_query.py +4 -4
- intentkit/skills/carv/schema.json +134 -137
- intentkit/skills/carv/token_info_and_price.py +6 -6
- intentkit/skills/casino/__init__.py +4 -15
- intentkit/skills/casino/base.py +1 -7
- intentkit/skills/casino/deck_draw.py +5 -8
- intentkit/skills/casino/deck_shuffle.py +6 -6
- intentkit/skills/casino/dice_roll.py +2 -4
- intentkit/skills/casino/schema.json +0 -1
- intentkit/skills/cdp/__init__.py +22 -84
- intentkit/skills/cdp/base.py +1 -7
- intentkit/skills/cdp/schema.json +11 -314
- intentkit/skills/chainlist/__init__.py +2 -7
- intentkit/skills/chainlist/base.py +1 -7
- intentkit/skills/chainlist/chain_lookup.py +18 -18
- intentkit/skills/chainlist/schema.json +3 -5
- intentkit/skills/common/__init__.py +2 -9
- intentkit/skills/common/base.py +1 -7
- intentkit/skills/common/current_time.py +1 -2
- intentkit/skills/common/schema.json +2 -2
- intentkit/skills/cookiefun/__init__.py +6 -9
- intentkit/skills/cookiefun/base.py +2 -7
- intentkit/skills/cookiefun/get_account_details.py +7 -7
- intentkit/skills/cookiefun/get_account_feed.py +19 -19
- intentkit/skills/cookiefun/get_account_smart_followers.py +7 -7
- intentkit/skills/cookiefun/get_sectors.py +3 -3
- intentkit/skills/cookiefun/schema.json +1 -3
- intentkit/skills/cookiefun/search_accounts.py +9 -9
- intentkit/skills/cryptocompare/__init__.py +7 -24
- intentkit/skills/cryptocompare/api.py +2 -3
- intentkit/skills/cryptocompare/base.py +10 -24
- intentkit/skills/cryptocompare/fetch_news.py +4 -5
- intentkit/skills/cryptocompare/fetch_price.py +6 -7
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +4 -5
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +4 -5
- intentkit/skills/cryptocompare/fetch_top_volume.py +4 -5
- intentkit/skills/cryptocompare/fetch_trading_signals.py +5 -6
- intentkit/skills/cryptocompare/schema.json +3 -3
- intentkit/skills/cryptopanic/__init__.py +7 -10
- intentkit/skills/cryptopanic/base.py +51 -55
- intentkit/skills/cryptopanic/fetch_crypto_news.py +4 -8
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +5 -7
- intentkit/skills/cryptopanic/schema.json +105 -103
- intentkit/skills/dapplooker/__init__.py +2 -9
- intentkit/skills/dapplooker/base.py +4 -9
- intentkit/skills/dapplooker/dapplooker_token_data.py +7 -7
- intentkit/skills/dapplooker/schema.json +3 -5
- intentkit/skills/defillama/__init__.py +24 -74
- intentkit/skills/defillama/api.py +6 -9
- intentkit/skills/defillama/base.py +8 -19
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +8 -10
- intentkit/skills/defillama/coins/fetch_block.py +6 -8
- intentkit/skills/defillama/coins/fetch_current_prices.py +8 -10
- intentkit/skills/defillama/coins/fetch_first_price.py +7 -9
- intentkit/skills/defillama/coins/fetch_historical_prices.py +9 -11
- intentkit/skills/defillama/coins/fetch_price_chart.py +9 -11
- intentkit/skills/defillama/coins/fetch_price_percentage.py +7 -9
- intentkit/skills/defillama/config/chains.py +1 -3
- intentkit/skills/defillama/fees/fetch_fees_overview.py +24 -26
- intentkit/skills/defillama/schema.json +5 -1
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +16 -18
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +8 -10
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +5 -7
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +7 -9
- intentkit/skills/defillama/tests/api_integration.test.py +1 -1
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +4 -6
- intentkit/skills/defillama/tvl/fetch_chains.py +9 -11
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +4 -6
- intentkit/skills/defillama/tvl/fetch_protocol.py +32 -38
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +3 -5
- intentkit/skills/defillama/tvl/fetch_protocols.py +37 -45
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +42 -48
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +35 -37
- intentkit/skills/defillama/volumes/fetch_options_overview.py +24 -28
- intentkit/skills/defillama/yields/fetch_pool_chart.py +10 -12
- intentkit/skills/defillama/yields/fetch_pools.py +26 -30
- intentkit/skills/dexscreener/__init__.py +97 -102
- intentkit/skills/dexscreener/base.py +125 -130
- intentkit/skills/dexscreener/get_pair_info.py +4 -5
- intentkit/skills/dexscreener/get_token_pairs.py +4 -5
- intentkit/skills/dexscreener/get_tokens_info.py +7 -8
- intentkit/skills/dexscreener/model/search_token_response.py +80 -82
- intentkit/skills/dexscreener/schema.json +91 -93
- intentkit/skills/dexscreener/search_token.py +182 -184
- intentkit/skills/dexscreener/utils.py +15 -14
- intentkit/skills/dune_analytics/__init__.py +7 -9
- intentkit/skills/dune_analytics/base.py +48 -52
- intentkit/skills/dune_analytics/fetch_kol_buys.py +5 -7
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +6 -8
- intentkit/skills/dune_analytics/schema.json +104 -99
- intentkit/skills/elfa/__init__.py +5 -18
- intentkit/skills/elfa/base.py +10 -14
- intentkit/skills/elfa/mention.py +19 -21
- intentkit/skills/elfa/schema.json +3 -2
- intentkit/skills/elfa/stats.py +4 -4
- intentkit/skills/elfa/tokens.py +12 -12
- intentkit/skills/elfa/utils.py +26 -28
- intentkit/skills/enso/__init__.py +11 -31
- intentkit/skills/enso/base.py +54 -35
- intentkit/skills/enso/best_yield.py +16 -24
- intentkit/skills/enso/networks.py +6 -11
- intentkit/skills/enso/prices.py +11 -13
- intentkit/skills/enso/route.py +34 -38
- intentkit/skills/enso/schema.json +3 -2
- intentkit/skills/enso/tokens.py +29 -38
- intentkit/skills/enso/wallet.py +76 -191
- intentkit/skills/erc20/__init__.py +50 -0
- intentkit/skills/erc20/base.py +11 -0
- intentkit/skills/erc20/erc20.svg +5 -0
- intentkit/skills/erc20/schema.json +74 -0
- intentkit/skills/erc721/__init__.py +53 -0
- intentkit/skills/erc721/base.py +11 -0
- intentkit/skills/erc721/erc721.svg +5 -0
- intentkit/skills/erc721/schema.json +90 -0
- intentkit/skills/firecrawl/__init__.py +5 -18
- intentkit/skills/firecrawl/base.py +4 -9
- intentkit/skills/firecrawl/clear.py +4 -8
- intentkit/skills/firecrawl/crawl.py +19 -19
- intentkit/skills/firecrawl/query.py +4 -3
- intentkit/skills/firecrawl/schema.json +2 -6
- intentkit/skills/firecrawl/scrape.py +17 -22
- intentkit/skills/firecrawl/utils.py +50 -42
- intentkit/skills/github/__init__.py +2 -7
- intentkit/skills/github/base.py +1 -7
- intentkit/skills/github/github_search.py +1 -2
- intentkit/skills/github/schema.json +3 -4
- intentkit/skills/heurist/__init__.py +8 -27
- intentkit/skills/heurist/base.py +4 -9
- intentkit/skills/heurist/image_generation_animagine_xl.py +13 -15
- intentkit/skills/heurist/image_generation_arthemy_comics.py +13 -15
- intentkit/skills/heurist/image_generation_arthemy_real.py +13 -15
- intentkit/skills/heurist/image_generation_braindance.py +13 -15
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +13 -15
- intentkit/skills/heurist/image_generation_flux_1_dev.py +13 -15
- intentkit/skills/heurist/image_generation_sdxl.py +13 -15
- intentkit/skills/heurist/schema.json +2 -2
- intentkit/skills/http/__init__.py +4 -15
- intentkit/skills/http/base.py +1 -7
- intentkit/skills/http/get.py +21 -16
- intentkit/skills/http/post.py +23 -18
- intentkit/skills/http/put.py +23 -18
- intentkit/skills/http/schema.json +4 -5
- intentkit/skills/lifi/__init__.py +8 -13
- intentkit/skills/lifi/base.py +3 -9
- intentkit/skills/lifi/schema.json +17 -8
- intentkit/skills/lifi/token_execute.py +150 -60
- intentkit/skills/lifi/token_quote.py +8 -10
- intentkit/skills/lifi/utils.py +104 -51
- intentkit/skills/moralis/__init__.py +6 -10
- intentkit/skills/moralis/api.py +6 -7
- intentkit/skills/moralis/base.py +5 -10
- intentkit/skills/moralis/fetch_chain_portfolio.py +10 -11
- intentkit/skills/moralis/fetch_nft_portfolio.py +22 -22
- intentkit/skills/moralis/fetch_solana_portfolio.py +11 -12
- intentkit/skills/moralis/fetch_wallet_portfolio.py +8 -9
- intentkit/skills/moralis/schema.json +7 -2
- intentkit/skills/morpho/__init__.py +52 -0
- intentkit/skills/morpho/base.py +11 -0
- intentkit/skills/morpho/morpho.svg +12 -0
- intentkit/skills/morpho/schema.json +73 -0
- intentkit/skills/nation/__init__.py +4 -9
- intentkit/skills/nation/base.py +5 -10
- intentkit/skills/nation/nft_check.py +3 -4
- intentkit/skills/nation/schema.json +4 -3
- intentkit/skills/onchain.py +30 -0
- intentkit/skills/openai/__init__.py +17 -18
- intentkit/skills/openai/base.py +10 -14
- intentkit/skills/openai/dalle_image_generation.py +4 -9
- intentkit/skills/openai/gpt_avatar_generator.py +102 -0
- intentkit/skills/openai/gpt_image_generation.py +5 -9
- intentkit/skills/openai/gpt_image_mini_generator.py +92 -0
- intentkit/skills/openai/gpt_image_to_image.py +5 -9
- intentkit/skills/openai/image_to_text.py +3 -7
- intentkit/skills/openai/schema.json +34 -3
- intentkit/skills/portfolio/__init__.py +11 -35
- intentkit/skills/portfolio/base.py +33 -19
- intentkit/skills/portfolio/schema.json +3 -5
- intentkit/skills/portfolio/token_balances.py +21 -21
- intentkit/skills/portfolio/wallet_approvals.py +17 -18
- intentkit/skills/portfolio/wallet_defi_positions.py +3 -3
- intentkit/skills/portfolio/wallet_history.py +31 -31
- intentkit/skills/portfolio/wallet_net_worth.py +13 -13
- intentkit/skills/portfolio/wallet_nfts.py +19 -19
- intentkit/skills/portfolio/wallet_profitability.py +18 -18
- intentkit/skills/portfolio/wallet_profitability_summary.py +5 -5
- intentkit/skills/portfolio/wallet_stats.py +3 -3
- intentkit/skills/portfolio/wallet_swaps.py +19 -19
- intentkit/skills/pyth/__init__.py +50 -0
- intentkit/skills/pyth/base.py +11 -0
- intentkit/skills/pyth/pyth.svg +6 -0
- intentkit/skills/pyth/schema.json +75 -0
- intentkit/skills/skills.toml +36 -0
- intentkit/skills/slack/__init__.py +5 -17
- intentkit/skills/slack/base.py +3 -9
- intentkit/skills/slack/get_channel.py +8 -8
- intentkit/skills/slack/get_message.py +9 -9
- intentkit/skills/slack/schedule_message.py +5 -5
- intentkit/skills/slack/schema.json +2 -2
- intentkit/skills/slack/send_message.py +3 -5
- intentkit/skills/supabase/__init__.py +7 -23
- intentkit/skills/supabase/base.py +1 -7
- intentkit/skills/supabase/delete_data.py +4 -4
- intentkit/skills/supabase/fetch_data.py +12 -12
- intentkit/skills/supabase/insert_data.py +4 -4
- intentkit/skills/supabase/invoke_function.py +6 -6
- intentkit/skills/supabase/schema.json +2 -3
- intentkit/skills/supabase/update_data.py +6 -6
- intentkit/skills/supabase/upsert_data.py +4 -4
- intentkit/skills/superfluid/__init__.py +53 -0
- intentkit/skills/superfluid/base.py +11 -0
- intentkit/skills/superfluid/schema.json +89 -0
- intentkit/skills/superfluid/superfluid.svg +6 -0
- intentkit/skills/system/__init__.py +7 -24
- intentkit/skills/system/add_autonomous_task.py +10 -12
- intentkit/skills/system/delete_autonomous_task.py +2 -2
- intentkit/skills/system/edit_autonomous_task.py +14 -18
- intentkit/skills/system/list_autonomous_tasks.py +3 -5
- intentkit/skills/system/read_agent_api_key.py +6 -4
- intentkit/skills/system/regenerate_agent_api_key.py +6 -4
- intentkit/skills/system/schema.json +6 -8
- intentkit/skills/tavily/__init__.py +3 -12
- intentkit/skills/tavily/base.py +4 -9
- intentkit/skills/tavily/schema.json +3 -5
- intentkit/skills/tavily/tavily_extract.py +2 -4
- intentkit/skills/tavily/tavily_search.py +4 -6
- intentkit/skills/token/__init__.py +5 -10
- intentkit/skills/token/base.py +7 -11
- intentkit/skills/token/erc20_transfers.py +19 -19
- intentkit/skills/token/schema.json +3 -6
- intentkit/skills/token/token_analytics.py +3 -3
- intentkit/skills/token/token_price.py +13 -13
- intentkit/skills/token/token_search.py +9 -9
- intentkit/skills/twitter/__init__.py +11 -35
- intentkit/skills/twitter/base.py +22 -34
- intentkit/skills/twitter/follow_user.py +2 -6
- intentkit/skills/twitter/get_mentions.py +5 -12
- intentkit/skills/twitter/get_timeline.py +4 -12
- intentkit/skills/twitter/get_user_by_username.py +2 -6
- intentkit/skills/twitter/get_user_tweets.py +5 -13
- intentkit/skills/twitter/like_tweet.py +2 -6
- intentkit/skills/twitter/post_tweet.py +6 -9
- intentkit/skills/twitter/reply_tweet.py +6 -9
- intentkit/skills/twitter/retweet.py +2 -6
- intentkit/skills/twitter/schema.json +1 -0
- intentkit/skills/twitter/search_tweets.py +4 -12
- intentkit/skills/unrealspeech/__init__.py +2 -7
- intentkit/skills/unrealspeech/base.py +2 -8
- intentkit/skills/unrealspeech/schema.json +2 -5
- intentkit/skills/unrealspeech/text_to_speech.py +8 -8
- intentkit/skills/venice_audio/__init__.py +98 -106
- intentkit/skills/venice_audio/base.py +117 -121
- intentkit/skills/venice_audio/input.py +41 -41
- intentkit/skills/venice_audio/schema.json +151 -152
- intentkit/skills/venice_audio/venice_audio.py +38 -21
- intentkit/skills/venice_image/__init__.py +147 -154
- intentkit/skills/venice_image/api.py +138 -138
- intentkit/skills/venice_image/base.py +185 -192
- intentkit/skills/venice_image/config.py +33 -35
- intentkit/skills/venice_image/image_enhance/image_enhance.py +2 -3
- intentkit/skills/venice_image/image_enhance/image_enhance_base.py +21 -23
- intentkit/skills/venice_image/image_enhance/image_enhance_input.py +38 -40
- intentkit/skills/venice_image/image_generation/image_generation_base.py +11 -10
- intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -27
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -158
- intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -26
- intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -28
- intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -28
- intentkit/skills/venice_image/image_upscale/image_upscale.py +3 -3
- intentkit/skills/venice_image/image_upscale/image_upscale_base.py +21 -23
- intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -22
- intentkit/skills/venice_image/image_vision/image_vision.py +2 -2
- intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -17
- intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -9
- intentkit/skills/venice_image/schema.json +267 -267
- intentkit/skills/venice_image/utils.py +77 -78
- intentkit/skills/web_scraper/__init__.py +5 -18
- intentkit/skills/web_scraper/base.py +21 -7
- intentkit/skills/web_scraper/document_indexer.py +7 -6
- intentkit/skills/web_scraper/schema.json +2 -6
- intentkit/skills/web_scraper/scrape_and_index.py +15 -15
- intentkit/skills/web_scraper/utils.py +62 -63
- intentkit/skills/web_scraper/website_indexer.py +17 -19
- intentkit/skills/weth/__init__.py +49 -0
- intentkit/skills/weth/base.py +11 -0
- intentkit/skills/weth/schema.json +58 -0
- intentkit/skills/weth/weth.svg +6 -0
- intentkit/skills/wow/__init__.py +51 -0
- intentkit/skills/wow/base.py +11 -0
- intentkit/skills/wow/schema.json +89 -0
- intentkit/skills/wow/wow.svg +7 -0
- intentkit/skills/x402/__init__.py +58 -0
- intentkit/skills/x402/base.py +99 -0
- intentkit/skills/x402/http_request.py +117 -0
- intentkit/skills/x402/schema.json +40 -0
- intentkit/skills/x402/x402.webp +0 -0
- intentkit/skills/xmtp/__init__.py +4 -15
- intentkit/skills/xmtp/base.py +5 -5
- intentkit/skills/xmtp/price.py +7 -6
- intentkit/skills/xmtp/schema.json +69 -71
- intentkit/skills/xmtp/swap.py +6 -8
- intentkit/skills/xmtp/transfer.py +4 -6
- intentkit/utils/__init__.py +4 -0
- intentkit/utils/chain.py +198 -96
- intentkit/utils/ens.py +135 -0
- intentkit/utils/error.py +5 -2
- intentkit/utils/logging.py +9 -11
- intentkit/utils/schema.py +100 -0
- intentkit/utils/slack_alert.py +8 -8
- intentkit/utils/tx.py +16 -8
- intentkit/uv.lock +3377 -0
- {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/METADATA +13 -15
- intentkit-0.8.34.dev7.dist-info/RECORD +478 -0
- intentkit-0.8.34.dev7.dist-info/licenses/LICENSE +21 -0
- intentkit/core/node.py +0 -215
- intentkit/models/conversation.py +0 -286
- intentkit/models/generator.py +0 -347
- intentkit/skills/cdp/get_balance.py +0 -110
- intentkit/skills/cdp/swap.py +0 -121
- intentkit/skills/moralis/tests/__init__.py +0 -0
- intentkit/skills/moralis/tests/test_wallet.py +0 -511
- intentkit-0.7.5.dev3.dist-info/RECORD +0 -424
- {intentkit-0.7.5.dev3.dist-info/licenses → intentkit}/LICENSE +0 -0
- {intentkit-0.7.5.dev3.dist-info → intentkit-0.8.34.dev7.dist-info}/WHEEL +0 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any
|
|
2
2
|
|
|
3
3
|
import httpx
|
|
4
4
|
from pydantic import BaseModel, Field
|
|
5
5
|
|
|
6
|
-
from intentkit.abstracts.skill import SkillStoreABC
|
|
7
6
|
from intentkit.skills.lifi.base import LiFiBaseTool
|
|
8
7
|
from intentkit.skills.lifi.utils import (
|
|
9
8
|
LIFI_API_URL,
|
|
@@ -53,21 +52,20 @@ class TokenQuote(LiFiBaseTool):
|
|
|
53
52
|
"Use this tool to check rates, fees, and estimated time for token transfers without executing them.\n"
|
|
54
53
|
"Supports all major chains like Ethereum, Polygon, Arbitrum, Optimism, Base, and more."
|
|
55
54
|
)
|
|
56
|
-
args_schema:
|
|
55
|
+
args_schema: type[BaseModel] = TokenQuoteInput
|
|
57
56
|
api_url: str = LIFI_API_URL
|
|
58
57
|
|
|
59
58
|
# Configuration options
|
|
60
59
|
default_slippage: float = 0.03
|
|
61
|
-
allowed_chains:
|
|
60
|
+
allowed_chains: list[str] | None = None
|
|
62
61
|
|
|
63
62
|
def __init__(
|
|
64
63
|
self,
|
|
65
|
-
skill_store: SkillStoreABC,
|
|
66
64
|
default_slippage: float = 0.03,
|
|
67
|
-
allowed_chains:
|
|
68
|
-
):
|
|
65
|
+
allowed_chains: list[str] | None = None,
|
|
66
|
+
) -> None:
|
|
69
67
|
"""Initialize the TokenQuote skill with configuration options."""
|
|
70
|
-
super().__init__(
|
|
68
|
+
super().__init__()
|
|
71
69
|
self.default_slippage = default_slippage
|
|
72
70
|
self.allowed_chains = allowed_chains
|
|
73
71
|
|
|
@@ -78,7 +76,7 @@ class TokenQuote(LiFiBaseTool):
|
|
|
78
76
|
from_token: str,
|
|
79
77
|
to_token: str,
|
|
80
78
|
from_amount: str,
|
|
81
|
-
slippage: float = None,
|
|
79
|
+
slippage: float | None = None,
|
|
82
80
|
**kwargs,
|
|
83
81
|
) -> str:
|
|
84
82
|
"""Get a quote for token transfer."""
|
|
@@ -140,7 +138,7 @@ class TokenQuote(LiFiBaseTool):
|
|
|
140
138
|
self.logger.error("LiFi_Error: %s", str(e))
|
|
141
139
|
return f"An unexpected error occurred: {str(e)}"
|
|
142
140
|
|
|
143
|
-
def _format_quote_result(self, data:
|
|
141
|
+
def _format_quote_result(self, data: dict[str, Any]) -> str:
|
|
144
142
|
"""Format quote result into human-readable text."""
|
|
145
143
|
try:
|
|
146
144
|
# Get basic info
|
intentkit/skills/lifi/utils.py
CHANGED
|
@@ -4,7 +4,8 @@ LiFi Skills Utilities
|
|
|
4
4
|
Common utilities and helper functions for LiFi token transfer skills.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from decimal import ROUND_DOWN, Decimal, InvalidOperation
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
10
|
import httpx
|
|
10
11
|
from web3 import Web3
|
|
@@ -71,8 +72,8 @@ def validate_inputs(
|
|
|
71
72
|
to_token: str,
|
|
72
73
|
from_amount: str,
|
|
73
74
|
slippage: float,
|
|
74
|
-
allowed_chains:
|
|
75
|
-
) ->
|
|
75
|
+
allowed_chains: list[str] | None = None,
|
|
76
|
+
) -> str | None:
|
|
76
77
|
"""
|
|
77
78
|
Validate all input parameters for LiFi operations.
|
|
78
79
|
|
|
@@ -179,7 +180,7 @@ def handle_api_response(
|
|
|
179
180
|
from_chain: str,
|
|
180
181
|
to_token: str,
|
|
181
182
|
to_chain: str,
|
|
182
|
-
) ->
|
|
183
|
+
) -> tuple[dict[str, Any] | None, str | None]:
|
|
183
184
|
"""
|
|
184
185
|
Handle LiFi API response and return data or error message.
|
|
185
186
|
|
|
@@ -293,17 +294,20 @@ def convert_chain_to_id(chain: str) -> int:
|
|
|
293
294
|
|
|
294
295
|
|
|
295
296
|
def convert_amount_to_wei(amount: str, token_symbol: str = "ETH") -> str:
|
|
296
|
-
"""
|
|
297
|
-
Convert human-readable amount to wei format for LiFi API.
|
|
297
|
+
"""Convert a token amount into the smallest denomination expected by LiFi."""
|
|
298
298
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
if amount is None:
|
|
300
|
+
raise ValueError("Amount is required")
|
|
301
|
+
|
|
302
|
+
normalized_amount = amount.strip()
|
|
303
|
+
if not normalized_amount:
|
|
304
|
+
raise ValueError("Amount cannot be empty")
|
|
305
|
+
|
|
306
|
+
# If the user already provided an integer amount without a decimal point,
|
|
307
|
+
# assume it is already in the token's smallest denomination.
|
|
308
|
+
if normalized_amount.isdigit():
|
|
309
|
+
return normalized_amount
|
|
302
310
|
|
|
303
|
-
Returns:
|
|
304
|
-
Amount in wei format as string
|
|
305
|
-
"""
|
|
306
|
-
# Default decimals for common tokens
|
|
307
311
|
token_decimals = {
|
|
308
312
|
"ETH": 18,
|
|
309
313
|
"USDC": 6,
|
|
@@ -318,13 +322,16 @@ def convert_amount_to_wei(amount: str, token_symbol: str = "ETH") -> str:
|
|
|
318
322
|
decimals = token_decimals.get(token_symbol.upper(), 18)
|
|
319
323
|
|
|
320
324
|
try:
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
decimal_amount = Decimal(normalized_amount)
|
|
326
|
+
scaled_amount = (decimal_amount * (Decimal(10) ** decimals)).quantize(
|
|
327
|
+
Decimal("1"),
|
|
328
|
+
rounding=ROUND_DOWN,
|
|
329
|
+
)
|
|
330
|
+
return str(int(scaled_amount))
|
|
331
|
+
except (InvalidOperation, ValueError, TypeError):
|
|
332
|
+
# If conversion fails, fall back to the original value to avoid
|
|
333
|
+
# accidentally submitting an incorrect amount.
|
|
334
|
+
return normalized_amount
|
|
328
335
|
|
|
329
336
|
|
|
330
337
|
def build_quote_params(
|
|
@@ -334,8 +341,8 @@ def build_quote_params(
|
|
|
334
341
|
to_token: str,
|
|
335
342
|
from_amount: str,
|
|
336
343
|
slippage: float,
|
|
337
|
-
from_address:
|
|
338
|
-
) ->
|
|
344
|
+
from_address: str | None = None,
|
|
345
|
+
) -> dict[str, Any]:
|
|
339
346
|
"""
|
|
340
347
|
Build parameters for LiFi quote API request.
|
|
341
348
|
|
|
@@ -350,15 +357,12 @@ def build_quote_params(
|
|
|
350
357
|
Raises:
|
|
351
358
|
ValueError: If chain identifiers are not recognized
|
|
352
359
|
"""
|
|
353
|
-
# Convert amount to wei format for API
|
|
354
|
-
wei_amount = convert_amount_to_wei(from_amount, from_token)
|
|
355
|
-
|
|
356
360
|
return {
|
|
357
361
|
"fromChain": convert_chain_to_id(from_chain),
|
|
358
362
|
"toChain": convert_chain_to_id(to_chain),
|
|
359
363
|
"fromToken": from_token,
|
|
360
364
|
"toToken": to_token,
|
|
361
|
-
"fromAmount":
|
|
365
|
+
"fromAmount": convert_amount_to_wei(from_amount, from_token),
|
|
362
366
|
"fromAddress": from_address or DUMMY_ADDRESS,
|
|
363
367
|
"slippage": slippage,
|
|
364
368
|
}
|
|
@@ -381,38 +385,87 @@ def is_native_token(token_address: str) -> bool:
|
|
|
381
385
|
)
|
|
382
386
|
|
|
383
387
|
|
|
384
|
-
def
|
|
385
|
-
"""
|
|
386
|
-
Prepare transaction parameters for CDP wallet provider.
|
|
388
|
+
def _convert_hex_or_decimal(value: Any) -> int | None:
|
|
389
|
+
"""Convert LiFi transaction numeric values into integers."""
|
|
387
390
|
|
|
388
|
-
|
|
389
|
-
|
|
391
|
+
if value is None:
|
|
392
|
+
return None
|
|
390
393
|
|
|
391
|
-
|
|
392
|
-
|
|
394
|
+
if isinstance(value, int):
|
|
395
|
+
return value
|
|
396
|
+
|
|
397
|
+
if isinstance(value, str):
|
|
398
|
+
stripped = value.strip()
|
|
399
|
+
if not stripped:
|
|
400
|
+
return None
|
|
401
|
+
if stripped.startswith("0x"):
|
|
402
|
+
return int(stripped, 16)
|
|
403
|
+
try:
|
|
404
|
+
return int(Decimal(stripped))
|
|
405
|
+
except (InvalidOperation, ValueError):
|
|
406
|
+
return None
|
|
407
|
+
|
|
408
|
+
return None
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def prepare_transaction_params(
|
|
412
|
+
transaction_request: dict[str, Any],
|
|
413
|
+
wallet_address: str | None = None,
|
|
414
|
+
) -> dict[str, Any]:
|
|
415
|
+
"""Prepare transaction parameters for the CDP wallet provider."""
|
|
393
416
|
|
|
394
|
-
Raises:
|
|
395
|
-
Exception: If required parameters are missing
|
|
396
|
-
"""
|
|
397
417
|
to_address = transaction_request.get("to")
|
|
398
|
-
value = transaction_request.get("value", "
|
|
418
|
+
value = transaction_request.get("value", "0x0")
|
|
399
419
|
data = transaction_request.get("data", "0x")
|
|
400
420
|
|
|
401
421
|
if not to_address:
|
|
402
|
-
raise Exception("
|
|
403
|
-
|
|
404
|
-
# Convert value to integer if it's a string
|
|
405
|
-
if isinstance(value, str):
|
|
406
|
-
value = int(value, 16) if value.startswith("0x") else int(value)
|
|
422
|
+
raise Exception("Transaction request is missing destination address")
|
|
407
423
|
|
|
408
|
-
|
|
424
|
+
tx_params: dict[str, Any] = {
|
|
409
425
|
"to": Web3.to_checksum_address(to_address),
|
|
410
|
-
"value": value,
|
|
411
426
|
"data": data,
|
|
412
427
|
}
|
|
413
428
|
|
|
429
|
+
int_value = _convert_hex_or_decimal(value)
|
|
430
|
+
if int_value is not None:
|
|
431
|
+
tx_params["value"] = int_value
|
|
432
|
+
|
|
433
|
+
chain_id = _convert_hex_or_decimal(transaction_request.get("chainId"))
|
|
434
|
+
if chain_id is not None:
|
|
435
|
+
tx_params["chainId"] = chain_id
|
|
436
|
+
|
|
437
|
+
gas_limit = _convert_hex_or_decimal(
|
|
438
|
+
transaction_request.get("gasLimit") or transaction_request.get("gas")
|
|
439
|
+
)
|
|
440
|
+
if gas_limit is not None:
|
|
441
|
+
tx_params["gas"] = gas_limit
|
|
442
|
+
|
|
443
|
+
gas_price = _convert_hex_or_decimal(transaction_request.get("gasPrice"))
|
|
444
|
+
if gas_price is not None:
|
|
445
|
+
tx_params["gasPrice"] = gas_price
|
|
446
|
+
|
|
447
|
+
max_fee_per_gas = _convert_hex_or_decimal(transaction_request.get("maxFeePerGas"))
|
|
448
|
+
if max_fee_per_gas is not None:
|
|
449
|
+
tx_params["maxFeePerGas"] = max_fee_per_gas
|
|
450
|
+
|
|
451
|
+
max_priority_fee_per_gas = _convert_hex_or_decimal(
|
|
452
|
+
transaction_request.get("maxPriorityFeePerGas")
|
|
453
|
+
)
|
|
454
|
+
if max_priority_fee_per_gas is not None:
|
|
455
|
+
tx_params["maxPriorityFeePerGas"] = max_priority_fee_per_gas
|
|
456
|
+
|
|
457
|
+
nonce = _convert_hex_or_decimal(transaction_request.get("nonce"))
|
|
458
|
+
if nonce is not None:
|
|
459
|
+
tx_params["nonce"] = nonce
|
|
460
|
+
|
|
461
|
+
from_address = transaction_request.get("from") or wallet_address
|
|
462
|
+
if from_address:
|
|
463
|
+
tx_params["from"] = Web3.to_checksum_address(from_address)
|
|
464
|
+
|
|
465
|
+
return tx_params
|
|
466
|
+
|
|
414
467
|
|
|
415
|
-
def format_quote_basic_info(data:
|
|
468
|
+
def format_quote_basic_info(data: dict[str, Any]) -> dict[str, Any]:
|
|
416
469
|
"""
|
|
417
470
|
Extract and format basic quote information.
|
|
418
471
|
|
|
@@ -450,7 +503,7 @@ def format_quote_basic_info(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
450
503
|
}
|
|
451
504
|
|
|
452
505
|
|
|
453
|
-
def format_fees_and_gas(data:
|
|
506
|
+
def format_fees_and_gas(data: dict[str, Any]) -> tuple[str, str]:
|
|
454
507
|
"""
|
|
455
508
|
Format fee and gas cost information from quote data.
|
|
456
509
|
|
|
@@ -464,7 +517,7 @@ def format_fees_and_gas(data: Dict[str, Any]) -> Tuple[str, str]:
|
|
|
464
517
|
|
|
465
518
|
# Extract gas and fee costs
|
|
466
519
|
gas_costs = estimate.get("gasCosts", [])
|
|
467
|
-
fee_costs = []
|
|
520
|
+
fee_costs: list[dict[str, Any]] = []
|
|
468
521
|
|
|
469
522
|
# Collect fee information from included steps
|
|
470
523
|
for step in data.get("includedSteps", []):
|
|
@@ -476,7 +529,7 @@ def format_fees_and_gas(data: Dict[str, Any]) -> Tuple[str, str]:
|
|
|
476
529
|
fees_text = ""
|
|
477
530
|
if fee_costs:
|
|
478
531
|
fees_text = "**Fees:**\n"
|
|
479
|
-
total_fee_usd = 0
|
|
532
|
+
total_fee_usd = 0.0
|
|
480
533
|
for fee in fee_costs:
|
|
481
534
|
fee_name = fee.get("name", "Unknown fee")
|
|
482
535
|
fee_amount = fee.get("amount", "0")
|
|
@@ -508,7 +561,7 @@ def format_fees_and_gas(data: Dict[str, Any]) -> Tuple[str, str]:
|
|
|
508
561
|
gas_text = ""
|
|
509
562
|
if gas_costs:
|
|
510
563
|
gas_text = "**Gas Cost:**\n"
|
|
511
|
-
total_gas_usd = 0
|
|
564
|
+
total_gas_usd = 0.0
|
|
512
565
|
for gas in gas_costs:
|
|
513
566
|
gas_amount = gas.get("amount", "0")
|
|
514
567
|
gas_token = gas.get("token", {}).get("symbol", "ETH")
|
|
@@ -531,7 +584,7 @@ def format_fees_and_gas(data: Dict[str, Any]) -> Tuple[str, str]:
|
|
|
531
584
|
return fees_text, gas_text
|
|
532
585
|
|
|
533
586
|
|
|
534
|
-
def format_route_info(data:
|
|
587
|
+
def format_route_info(data: dict[str, Any]) -> str:
|
|
535
588
|
"""
|
|
536
589
|
Format routing information from quote data.
|
|
537
590
|
|
|
@@ -628,7 +681,7 @@ def get_explorer_url(chain_id: int, tx_hash: str) -> str:
|
|
|
628
681
|
|
|
629
682
|
|
|
630
683
|
def format_transaction_result(
|
|
631
|
-
tx_hash: str, chain_id: int, token_info: dict = None
|
|
684
|
+
tx_hash: str, chain_id: int, token_info: dict[str, str] | None = None
|
|
632
685
|
) -> str:
|
|
633
686
|
"""
|
|
634
687
|
Format transaction result with explorer link.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Wallet Portfolio Skills for IntentKit."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import NotRequired, TypedDict
|
|
5
5
|
|
|
6
|
-
from intentkit.
|
|
6
|
+
from intentkit.config.config import config as system_config
|
|
7
7
|
from intentkit.skills.base import SkillConfig, SkillState
|
|
8
8
|
from intentkit.skills.moralis.base import WalletBaseTool
|
|
9
9
|
from intentkit.skills.moralis.fetch_chain_portfolio import FetchChainPortfolio
|
|
@@ -28,21 +28,19 @@ class Config(SkillConfig):
|
|
|
28
28
|
|
|
29
29
|
api_key: str
|
|
30
30
|
states: SkillStates
|
|
31
|
-
supported_chains: NotRequired[
|
|
31
|
+
supported_chains: NotRequired[dict[str, bool]] = {"evm": True, "solana": True}
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
async def get_skills(
|
|
35
35
|
config: "Config",
|
|
36
36
|
is_private: bool,
|
|
37
|
-
store: SkillStoreABC,
|
|
38
37
|
**_,
|
|
39
|
-
) ->
|
|
38
|
+
) -> list[WalletBaseTool]:
|
|
40
39
|
"""Get all Wallet Portfolio skills.
|
|
41
40
|
|
|
42
41
|
Args:
|
|
43
42
|
config: Skill configuration
|
|
44
43
|
is_private: Whether the request is from an authenticated user
|
|
45
|
-
store: Skill store for persistence
|
|
46
44
|
chain_provider: Optional chain provider for blockchain interactions
|
|
47
45
|
**_: Additional arguments
|
|
48
46
|
|
|
@@ -67,12 +65,12 @@ async def get_skills(
|
|
|
67
65
|
if config.get("api_key_provider") == "agent_owner":
|
|
68
66
|
api_key = config.get("api_key")
|
|
69
67
|
else:
|
|
70
|
-
api_key =
|
|
68
|
+
api_key = system_config.moralis_api_key
|
|
71
69
|
|
|
72
70
|
# Get each skill using the getter
|
|
73
71
|
result = []
|
|
74
72
|
for name in available_skills:
|
|
75
|
-
skill = get_wallet_skill(name, api_key
|
|
73
|
+
skill = get_wallet_skill(name, api_key)
|
|
76
74
|
if skill:
|
|
77
75
|
result.append(skill)
|
|
78
76
|
return result
|
|
@@ -81,7 +79,6 @@ async def get_skills(
|
|
|
81
79
|
def get_wallet_skill(
|
|
82
80
|
name: str,
|
|
83
81
|
api_key: str,
|
|
84
|
-
store: SkillStoreABC,
|
|
85
82
|
) -> WalletBaseTool:
|
|
86
83
|
"""Get a specific Wallet Portfolio skill by name.
|
|
87
84
|
|
|
@@ -106,5 +103,4 @@ def get_wallet_skill(
|
|
|
106
103
|
|
|
107
104
|
return skill_classes[name](
|
|
108
105
|
api_key=api_key,
|
|
109
|
-
skill_store=store,
|
|
110
106
|
)
|
intentkit/skills/moralis/api.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""API interface for wallet data providers (EVM chains and Solana)."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Dict
|
|
5
4
|
|
|
6
5
|
import httpx
|
|
7
6
|
|
|
@@ -163,7 +162,7 @@ async def fetch_net_worth(api_key: str, address: str) -> dict:
|
|
|
163
162
|
#############################################
|
|
164
163
|
|
|
165
164
|
|
|
166
|
-
async def fetch_solana_api(api_key: str, endpoint: str, params:
|
|
165
|
+
async def fetch_solana_api(api_key: str, endpoint: str, params: dict = None) -> dict:
|
|
167
166
|
"""Base function for Solana API calls using Moralis.
|
|
168
167
|
|
|
169
168
|
Args:
|
|
@@ -200,7 +199,7 @@ async def fetch_solana_api(api_key: str, endpoint: str, params: Dict = None) ->
|
|
|
200
199
|
|
|
201
200
|
async def get_solana_portfolio(
|
|
202
201
|
api_key: str, address: str, network: str = "mainnet"
|
|
203
|
-
) ->
|
|
202
|
+
) -> dict:
|
|
204
203
|
"""Get complete portfolio for a Solana wallet.
|
|
205
204
|
|
|
206
205
|
Args:
|
|
@@ -217,7 +216,7 @@ async def get_solana_portfolio(
|
|
|
217
216
|
|
|
218
217
|
async def get_solana_balance(
|
|
219
218
|
api_key: str, address: str, network: str = "mainnet"
|
|
220
|
-
) ->
|
|
219
|
+
) -> dict:
|
|
221
220
|
"""Get native SOL balance.
|
|
222
221
|
|
|
223
222
|
Args:
|
|
@@ -234,7 +233,7 @@ async def get_solana_balance(
|
|
|
234
233
|
|
|
235
234
|
async def get_solana_spl_tokens(
|
|
236
235
|
api_key: str, address: str, network: str = "mainnet"
|
|
237
|
-
) ->
|
|
236
|
+
) -> dict:
|
|
238
237
|
"""Get SPL token balances.
|
|
239
238
|
|
|
240
239
|
Args:
|
|
@@ -249,7 +248,7 @@ async def get_solana_spl_tokens(
|
|
|
249
248
|
return await fetch_solana_api(api_key, endpoint)
|
|
250
249
|
|
|
251
250
|
|
|
252
|
-
async def get_solana_nfts(api_key: str, address: str, network: str = "mainnet") ->
|
|
251
|
+
async def get_solana_nfts(api_key: str, address: str, network: str = "mainnet") -> dict:
|
|
253
252
|
"""Get NFTs owned by a Solana wallet.
|
|
254
253
|
|
|
255
254
|
Args:
|
|
@@ -266,7 +265,7 @@ async def get_solana_nfts(api_key: str, address: str, network: str = "mainnet")
|
|
|
266
265
|
|
|
267
266
|
async def get_token_price(
|
|
268
267
|
api_key: str, token_address: str, network: str = "mainnet"
|
|
269
|
-
) ->
|
|
268
|
+
) -> dict:
|
|
270
269
|
"""Get token price by mint address.
|
|
271
270
|
|
|
272
271
|
Args:
|
intentkit/skills/moralis/base.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
"""Base class for Wallet Portfolio tools."""
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from langchain.tools.base import ToolException
|
|
3
|
+
from langchain_core.tools.base import ToolException
|
|
6
4
|
from pydantic import BaseModel, Field
|
|
7
5
|
|
|
8
|
-
from intentkit.
|
|
6
|
+
from intentkit.config.config import config
|
|
9
7
|
from intentkit.skills.base import IntentKitSkill
|
|
10
8
|
|
|
11
9
|
# Chain ID to chain name mapping for EVM chains
|
|
@@ -29,13 +27,10 @@ class WalletBaseTool(IntentKitSkill):
|
|
|
29
27
|
|
|
30
28
|
name: str = Field(description="The name of the tool")
|
|
31
29
|
description: str = Field(description="A description of what the tool does")
|
|
32
|
-
args_schema:
|
|
33
|
-
skill_store: SkillStoreABC = Field(
|
|
34
|
-
description="The skill store for persisting data"
|
|
35
|
-
)
|
|
30
|
+
args_schema: type[BaseModel]
|
|
36
31
|
|
|
37
32
|
# Optional fields for blockchain providers
|
|
38
|
-
solana_networks:
|
|
33
|
+
solana_networks: list[str] | None = Field(
|
|
39
34
|
default=SOLANA_NETWORKS, description="Supported Solana networks"
|
|
40
35
|
)
|
|
41
36
|
|
|
@@ -44,7 +39,7 @@ class WalletBaseTool(IntentKitSkill):
|
|
|
44
39
|
skill_config = context.agent.skill_config(self.category)
|
|
45
40
|
api_key_provider = skill_config.get("api_key_provider")
|
|
46
41
|
if api_key_provider == "platform":
|
|
47
|
-
return
|
|
42
|
+
return config.moralis_api_key
|
|
48
43
|
# for backward compatibility, may only have api_key in skill_config
|
|
49
44
|
elif skill_config.get("api_key"):
|
|
50
45
|
return skill_config.get("api_key")
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""fetching wallet portfolio for a specific blockchain."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import List, Optional, Type
|
|
5
4
|
|
|
6
5
|
from pydantic import BaseModel, Field
|
|
7
6
|
|
|
@@ -27,7 +26,7 @@ class ChainTokenBalance(BaseModel):
|
|
|
27
26
|
contract_address: str = Field(..., description="Token contract address")
|
|
28
27
|
symbol: str = Field(..., description="Token symbol")
|
|
29
28
|
name: str = Field(..., description="Token name")
|
|
30
|
-
logo:
|
|
29
|
+
logo: str | None = Field(None, description="Token logo URL")
|
|
31
30
|
decimals: int = Field(..., description="Token decimals")
|
|
32
31
|
balance: float = Field(..., description="Token balance")
|
|
33
32
|
balance_raw: str = Field(..., description="Raw token balance")
|
|
@@ -38,12 +37,12 @@ class TokenApproval(BaseModel):
|
|
|
38
37
|
"""Model for token approval."""
|
|
39
38
|
|
|
40
39
|
token_address: str = Field(..., description="Token contract address")
|
|
41
|
-
token_symbol:
|
|
42
|
-
token_name:
|
|
40
|
+
token_symbol: str | None = Field(None, description="Token symbol")
|
|
41
|
+
token_name: str | None = Field(None, description="Token name")
|
|
43
42
|
spender: str = Field(..., description="Spender address (contract)")
|
|
44
|
-
spender_name:
|
|
43
|
+
spender_name: str | None = Field(None, description="Spender name if known")
|
|
45
44
|
allowance: str = Field(..., description="Raw approval amount")
|
|
46
|
-
allowance_formatted:
|
|
45
|
+
allowance_formatted: float | None = Field(
|
|
47
46
|
None, description="Formatted approval amount"
|
|
48
47
|
)
|
|
49
48
|
unlimited: bool = Field(False, description="Whether the approval is unlimited")
|
|
@@ -55,17 +54,17 @@ class ChainPortfolioOutput(BaseModel):
|
|
|
55
54
|
address: str = Field(..., description="Wallet address")
|
|
56
55
|
chain_id: int = Field(..., description="Chain ID")
|
|
57
56
|
chain_name: str = Field(..., description="Chain name")
|
|
58
|
-
native_token:
|
|
57
|
+
native_token: ChainTokenBalance | None = Field(
|
|
59
58
|
None, description="Native token balance"
|
|
60
59
|
)
|
|
61
|
-
tokens:
|
|
60
|
+
tokens: list[ChainTokenBalance] = Field(
|
|
62
61
|
default_factory=list, description="List of token balances"
|
|
63
62
|
)
|
|
64
63
|
total_usd_value: float = Field(0.0, description="Total USD value on this chain")
|
|
65
|
-
approvals:
|
|
64
|
+
approvals: list[TokenApproval] | None = Field(
|
|
66
65
|
None, description="Token approvals if requested"
|
|
67
66
|
)
|
|
68
|
-
error:
|
|
67
|
+
error: str | None = Field(None, description="Error message if any")
|
|
69
68
|
|
|
70
69
|
|
|
71
70
|
class FetchChainPortfolio(WalletBaseTool):
|
|
@@ -87,7 +86,7 @@ class FetchChainPortfolio(WalletBaseTool):
|
|
|
87
86
|
"- Token approvals (optional)\n"
|
|
88
87
|
"Use this tool whenever a user wants to see their holdings on a specific blockchain."
|
|
89
88
|
)
|
|
90
|
-
args_schema:
|
|
89
|
+
args_schema: type[BaseModel] = FetchChainPortfolioInput
|
|
91
90
|
|
|
92
91
|
async def _arun(
|
|
93
92
|
self, address: str, chain_id: int, include_approvals: bool = False, **kwargs
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
6
6
|
|
|
7
7
|
from pydantic import BaseModel, Field
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ class FetchNftPortfolioInput(BaseModel):
|
|
|
16
16
|
"""Input for FetchNftPortfolio tool."""
|
|
17
17
|
|
|
18
18
|
address: str = Field(..., description="Wallet address")
|
|
19
|
-
chain_id:
|
|
19
|
+
chain_id: int | None = Field(
|
|
20
20
|
None,
|
|
21
21
|
description="Chain ID (if not specified, fetches from all supported chains)",
|
|
22
22
|
)
|
|
@@ -26,7 +26,7 @@ class FetchNftPortfolioInput(BaseModel):
|
|
|
26
26
|
solana_network: str = Field(
|
|
27
27
|
default="mainnet", description="Solana network to use (mainnet or devnet)"
|
|
28
28
|
)
|
|
29
|
-
limit:
|
|
29
|
+
limit: int | None = Field(100, description="Maximum number of NFTs to return")
|
|
30
30
|
normalize_metadata: bool = Field(
|
|
31
31
|
True, description="Whether to normalize metadata across different standards"
|
|
32
32
|
)
|
|
@@ -35,12 +35,12 @@ class FetchNftPortfolioInput(BaseModel):
|
|
|
35
35
|
class NftMetadata(BaseModel):
|
|
36
36
|
"""Model for NFT metadata."""
|
|
37
37
|
|
|
38
|
-
name:
|
|
39
|
-
description:
|
|
40
|
-
image:
|
|
41
|
-
animation_url:
|
|
42
|
-
attributes:
|
|
43
|
-
external_url:
|
|
38
|
+
name: str | None = Field(None, description="NFT name")
|
|
39
|
+
description: str | None = Field(None, description="NFT description")
|
|
40
|
+
image: str | None = Field(None, description="NFT image URL")
|
|
41
|
+
animation_url: str | None = Field(None, description="NFT animation URL")
|
|
42
|
+
attributes: list[dict] | None = Field(None, description="NFT attributes/traits")
|
|
43
|
+
external_url: str | None = Field(None, description="External URL")
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class NftItem(BaseModel):
|
|
@@ -48,14 +48,14 @@ class NftItem(BaseModel):
|
|
|
48
48
|
|
|
49
49
|
token_id: str = Field(..., description="NFT token ID")
|
|
50
50
|
token_address: str = Field(..., description="NFT contract address")
|
|
51
|
-
contract_type:
|
|
51
|
+
contract_type: str | None = Field(
|
|
52
52
|
None, description="NFT contract type (ERC721, ERC1155, etc.)"
|
|
53
53
|
)
|
|
54
|
-
name:
|
|
55
|
-
symbol:
|
|
54
|
+
name: str | None = Field(None, description="NFT name")
|
|
55
|
+
symbol: str | None = Field(None, description="NFT symbol")
|
|
56
56
|
owner_of: str = Field(..., description="Owner address")
|
|
57
|
-
metadata:
|
|
58
|
-
floor_price:
|
|
57
|
+
metadata: NftMetadata | None = Field(None, description="NFT metadata")
|
|
58
|
+
floor_price: float | None = Field(None, description="Floor price if available")
|
|
59
59
|
chain: str = Field("eth", description="Blockchain network")
|
|
60
60
|
|
|
61
61
|
|
|
@@ -63,13 +63,13 @@ class NftPortfolioOutput(BaseModel):
|
|
|
63
63
|
"""Output for FetchNftPortfolio tool."""
|
|
64
64
|
|
|
65
65
|
address: str = Field(..., description="Wallet address")
|
|
66
|
-
nfts:
|
|
66
|
+
nfts: list[NftItem] = Field(default_factory=list, description="List of NFT items")
|
|
67
67
|
total_count: int = Field(0, description="Total count of NFTs")
|
|
68
|
-
chains:
|
|
68
|
+
chains: list[str] = Field(
|
|
69
69
|
default_factory=list, description="Chains included in the response"
|
|
70
70
|
)
|
|
71
|
-
cursor:
|
|
72
|
-
error:
|
|
71
|
+
cursor: str | None = Field(None, description="Cursor for pagination")
|
|
72
|
+
error: str | None = Field(None, description="Error message if any")
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
class FetchNftPortfolio(WalletBaseTool):
|
|
@@ -90,12 +90,12 @@ class FetchNftPortfolio(WalletBaseTool):
|
|
|
90
90
|
"- Floor prices if available\n"
|
|
91
91
|
"Use this tool whenever a user asks about their NFTs or digital collectibles."
|
|
92
92
|
)
|
|
93
|
-
args_schema:
|
|
93
|
+
args_schema: type[BaseModel] = FetchNftPortfolioInput
|
|
94
94
|
|
|
95
95
|
async def _arun(
|
|
96
96
|
self,
|
|
97
97
|
address: str,
|
|
98
|
-
chain_id:
|
|
98
|
+
chain_id: int | None = None,
|
|
99
99
|
include_solana: bool = False,
|
|
100
100
|
solana_network: str = "mainnet",
|
|
101
101
|
limit: int = 100,
|
|
@@ -156,7 +156,7 @@ class FetchNftPortfolio(WalletBaseTool):
|
|
|
156
156
|
chain_id: int,
|
|
157
157
|
limit: int,
|
|
158
158
|
normalize_metadata: bool,
|
|
159
|
-
result:
|
|
159
|
+
result: dict[str, Any],
|
|
160
160
|
) -> None:
|
|
161
161
|
"""Fetch NFTs from an EVM chain.
|
|
162
162
|
|
|
@@ -222,7 +222,7 @@ class FetchNftPortfolio(WalletBaseTool):
|
|
|
222
222
|
result["nfts"].append(nft_item)
|
|
223
223
|
|
|
224
224
|
async def _fetch_solana_nfts(
|
|
225
|
-
self, address: str, network: str, limit: int, result:
|
|
225
|
+
self, address: str, network: str, limit: int, result: dict[str, Any]
|
|
226
226
|
) -> None:
|
|
227
227
|
"""Fetch NFTs from Solana.
|
|
228
228
|
|