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
intentkit/utils/ens.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Utilities for resolving ENS domains to wallet addresses."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
from ens import ENS
|
|
9
|
+
from web3 import Web3
|
|
10
|
+
from web3.middleware import ExtraDataToPOAMiddleware
|
|
11
|
+
|
|
12
|
+
from intentkit.config.config import config
|
|
13
|
+
from intentkit.models.redis import get_redis
|
|
14
|
+
from intentkit.utils.error import IntentKitAPIError
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
_CACHE_PREFIX = "intentkit:ens:"
|
|
19
|
+
_CACHE_TTL_SECONDS = 4 * 60 * 60
|
|
20
|
+
|
|
21
|
+
_NETWORKS_BY_SUFFIX: dict[str, tuple[str, ...]] = {
|
|
22
|
+
".base.eth": ("base-mainnet", "ethereum-mainnet"),
|
|
23
|
+
".eth": ("ethereum-mainnet",),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_POA_NETWORK_PREFIXES: tuple[str, ...] = ("base",)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def resolve_ens_to_address(name: str) -> str:
|
|
30
|
+
"""Resolve an ENS domain to a checksum wallet address.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
name: ENS name to resolve.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
The checksum wallet address associated with the ENS name.
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
IntentKitAPIError: If the ENS name cannot be resolved to a wallet address.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
normalized = name.strip().lower()
|
|
43
|
+
if not normalized:
|
|
44
|
+
raise IntentKitAPIError(404, "ENSNameNotFound", "ENS name is empty.")
|
|
45
|
+
|
|
46
|
+
redis_client = None
|
|
47
|
+
cache_key = f"{_CACHE_PREFIX}{normalized}"
|
|
48
|
+
try:
|
|
49
|
+
redis_client = get_redis()
|
|
50
|
+
except Exception: # Redis is optional; ignore if unavailable
|
|
51
|
+
redis_client = None
|
|
52
|
+
|
|
53
|
+
if redis_client is not None:
|
|
54
|
+
cached_address = await redis_client.get(cache_key)
|
|
55
|
+
if cached_address:
|
|
56
|
+
return cached_address
|
|
57
|
+
|
|
58
|
+
networks = _networks_for_name(normalized)
|
|
59
|
+
if not networks:
|
|
60
|
+
raise IntentKitAPIError(
|
|
61
|
+
404,
|
|
62
|
+
"ENSNameNotFound",
|
|
63
|
+
"Unsupported ENS name suffix.",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
for network in networks:
|
|
67
|
+
address = await _resolve_on_network(normalized, network)
|
|
68
|
+
if address:
|
|
69
|
+
if redis_client is not None:
|
|
70
|
+
try:
|
|
71
|
+
await redis_client.set(cache_key, address, ex=_CACHE_TTL_SECONDS)
|
|
72
|
+
except Exception as exc: # pragma: no cover - optional cache
|
|
73
|
+
logger.debug("Failed to cache ENS resolution: %s", exc)
|
|
74
|
+
return address
|
|
75
|
+
|
|
76
|
+
raise IntentKitAPIError(
|
|
77
|
+
404,
|
|
78
|
+
"ENSNameNotFound",
|
|
79
|
+
f"ENS name {name} could not be resolved.",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _networks_for_name(name: str) -> tuple[str, ...]:
|
|
84
|
+
for suffix, networks in _NETWORKS_BY_SUFFIX.items():
|
|
85
|
+
if name.endswith(suffix):
|
|
86
|
+
return networks
|
|
87
|
+
return tuple()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _requires_poa_middleware(network: str) -> bool:
|
|
91
|
+
return network.startswith(_POA_NETWORK_PREFIXES)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _build_ens_client(rpc_url: str, network: str) -> ENS:
|
|
95
|
+
web3_client = Web3(Web3.HTTPProvider(rpc_url))
|
|
96
|
+
if _requires_poa_middleware(network):
|
|
97
|
+
web3_client.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
|
|
98
|
+
|
|
99
|
+
return ENS.from_web3(web3_client)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
async def _resolve_on_network(name: str, network: str) -> str | None:
|
|
103
|
+
chain_provider = getattr(config, "chain_provider", None)
|
|
104
|
+
if chain_provider is None:
|
|
105
|
+
logger.debug("No chain provider configured; cannot resolve ENS name.")
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
chain_config = chain_provider.get_chain_config(network)
|
|
110
|
+
except Exception as exc: # pragma: no cover - dependent on external config
|
|
111
|
+
logger.debug("Chain config for %s unavailable: %s", network, exc)
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
rpc_url = chain_config.ens_url or chain_config.rpc_url
|
|
115
|
+
if not rpc_url:
|
|
116
|
+
logger.debug("No RPC/ENS URL configured for %s", network)
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
def _resolve() -> str | None:
|
|
120
|
+
ens_client = _build_ens_client(rpc_url, network)
|
|
121
|
+
try:
|
|
122
|
+
resolved = ens_client.address(name)
|
|
123
|
+
except Exception as exc: # pragma: no cover - dependent on external provider
|
|
124
|
+
logger.debug("Error resolving %s on %s: %s", name, network, exc)
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
if not resolved:
|
|
128
|
+
return None
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
return Web3.to_checksum_address(resolved)
|
|
132
|
+
except ValueError:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
return await asyncio.to_thread(_resolve)
|
intentkit/utils/error.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from
|
|
2
|
+
from collections.abc import Sequence
|
|
3
3
|
|
|
4
4
|
from fastapi.exceptions import RequestValidationError
|
|
5
5
|
from fastapi.utils import is_body_allowed_for_status_code
|
|
@@ -17,12 +17,15 @@ logger = logging.getLogger(__name__)
|
|
|
17
17
|
class RateLimitExceeded(Exception):
|
|
18
18
|
"""Rate limit exceeded"""
|
|
19
19
|
|
|
20
|
-
def __init__(self, message:
|
|
20
|
+
def __init__(self, message: str | None = "Rate limit exceeded"):
|
|
21
21
|
self.message = message
|
|
22
22
|
super().__init__(self.message)
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class IntentKitAPIError(Exception):
|
|
26
|
+
"""All 3 parameters: status_code, key and message is required.
|
|
27
|
+
The key is PascalCase string, to allow the frontend to test errors."""
|
|
28
|
+
|
|
26
29
|
def __init__(self, status_code: int, key: str, message: str):
|
|
27
30
|
self.key = key
|
|
28
31
|
self.message = message
|
intentkit/utils/logging.py
CHANGED
|
@@ -4,17 +4,17 @@ Logging configuration module
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
|
-
from
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import override
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class JsonFormatter(logging.Formatter):
|
|
11
|
-
def __init__(
|
|
12
|
-
self, filter_func: Optional[Callable[[logging.LogRecord], bool]] = None
|
|
13
|
-
):
|
|
12
|
+
def __init__(self, filter_func: Callable[[logging.LogRecord], bool] | None = None):
|
|
14
13
|
super().__init__()
|
|
15
14
|
self.filter_func = filter_func
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
@override
|
|
17
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
18
18
|
if self.filter_func and not self.filter_func(record):
|
|
19
19
|
return ""
|
|
20
20
|
|
|
@@ -24,17 +24,15 @@ class JsonFormatter(logging.Formatter):
|
|
|
24
24
|
"level": record.levelname,
|
|
25
25
|
"message": record.getMessage(),
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
if
|
|
29
|
-
log_obj.update(
|
|
30
|
-
elif record.__dict__.get("extra"):
|
|
31
|
-
log_obj.update(record.__dict__["extra"])
|
|
27
|
+
extra = record.__dict__.get("extra")
|
|
28
|
+
if isinstance(extra, dict):
|
|
29
|
+
log_obj.update(extra)
|
|
32
30
|
if record.exc_info:
|
|
33
31
|
log_obj["exc_info"] = self.formatException(record.exc_info)
|
|
34
32
|
return json.dumps(log_obj)
|
|
35
33
|
|
|
36
34
|
|
|
37
|
-
def setup_logging(env: str, debug: bool = False):
|
|
35
|
+
def setup_logging(env: str, debug: bool = False) -> None:
|
|
38
36
|
"""
|
|
39
37
|
Setup global logging configuration.
|
|
40
38
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""JSON Schema utilities for IntentKit.
|
|
2
|
+
|
|
3
|
+
This module provides utilities for working with JSON schemas, including
|
|
4
|
+
resolving $defs references and generating nested schemas.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import copy
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def resolve_schema_refs(schema: dict[str, Any]) -> dict[str, Any]:
|
|
12
|
+
"""Recursively resolve $defs references in a JSON schema.
|
|
13
|
+
|
|
14
|
+
This function takes a JSON schema with $defs references and returns
|
|
15
|
+
a fully nested schema without any $ref pointers. This is useful for
|
|
16
|
+
creating schemas that can be easily consumed by external systems
|
|
17
|
+
that don't support JSON Schema references.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
schema: The JSON schema dictionary that may contain $defs and $ref
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
dict: A new schema with all $ref resolved to nested objects
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> schema = {
|
|
27
|
+
... "type": "object",
|
|
28
|
+
... "properties": {
|
|
29
|
+
... "user": {"$ref": "#/$defs/User"}
|
|
30
|
+
... },
|
|
31
|
+
... "$defs": {
|
|
32
|
+
... "User": {
|
|
33
|
+
... "type": "object",
|
|
34
|
+
... "properties": {"name": {"type": "string"}}
|
|
35
|
+
... }
|
|
36
|
+
... }
|
|
37
|
+
... }
|
|
38
|
+
>>> resolved = resolve_schema_refs(schema)
|
|
39
|
+
>>> # resolved will have the User definition inlined
|
|
40
|
+
"""
|
|
41
|
+
# Deep copy to avoid modifying the original
|
|
42
|
+
resolved_schema = copy.deepcopy(schema)
|
|
43
|
+
|
|
44
|
+
# Extract $defs if they exist
|
|
45
|
+
defs = resolved_schema.pop("$defs", {})
|
|
46
|
+
|
|
47
|
+
def resolve_refs(obj: Any, defs_dict: dict[str, Any]) -> Any:
|
|
48
|
+
"""Recursively resolve $ref in an object."""
|
|
49
|
+
if isinstance(obj, dict):
|
|
50
|
+
if "$ref" in obj:
|
|
51
|
+
ref_path = obj["$ref"]
|
|
52
|
+
if ref_path.startswith("#/$defs/"):
|
|
53
|
+
def_name = ref_path.replace("#/$defs/", "")
|
|
54
|
+
if def_name in defs_dict:
|
|
55
|
+
# Recursively resolve the referenced definition
|
|
56
|
+
resolved_def = resolve_refs(defs_dict[def_name], defs_dict)
|
|
57
|
+
return resolved_def
|
|
58
|
+
else:
|
|
59
|
+
# Keep the reference if definition not found
|
|
60
|
+
return obj
|
|
61
|
+
else:
|
|
62
|
+
# Keep non-$defs references as is
|
|
63
|
+
return obj
|
|
64
|
+
else:
|
|
65
|
+
# Recursively process all values in the dictionary
|
|
66
|
+
return {
|
|
67
|
+
key: resolve_refs(value, defs_dict) for key, value in obj.items()
|
|
68
|
+
}
|
|
69
|
+
elif isinstance(obj, list):
|
|
70
|
+
# Recursively process all items in the list
|
|
71
|
+
return [resolve_refs(item, defs_dict) for item in obj]
|
|
72
|
+
else:
|
|
73
|
+
# Return primitive values as is
|
|
74
|
+
return obj
|
|
75
|
+
|
|
76
|
+
# Resolve all references in the schema
|
|
77
|
+
return resolve_refs(resolved_schema, defs)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def create_array_schema(
|
|
81
|
+
item_schema: dict[str, Any], resolve_refs: bool = True
|
|
82
|
+
) -> dict[str, Any]:
|
|
83
|
+
"""Create an array schema with the given item schema.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
item_schema: The schema for array items
|
|
87
|
+
resolve_refs: Whether to resolve $defs references in the item schema
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
dict: Array schema with resolved item schema
|
|
91
|
+
"""
|
|
92
|
+
if resolve_refs:
|
|
93
|
+
resolved_item_schema = resolve_schema_refs(item_schema)
|
|
94
|
+
else:
|
|
95
|
+
resolved_item_schema = item_schema
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
"type": "array",
|
|
99
|
+
"items": resolved_item_schema,
|
|
100
|
+
}
|
intentkit/utils/slack_alert.py
CHANGED
|
@@ -3,7 +3,7 @@ Slack notification module for sending messages to Slack channels.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Any, Sequence
|
|
7
7
|
|
|
8
8
|
from slack_sdk import WebClient
|
|
9
9
|
from slack_sdk.errors import SlackApiError
|
|
@@ -11,9 +11,9 @@ from slack_sdk.errors import SlackApiError
|
|
|
11
11
|
logger = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
# Global variables for Slack configuration
|
|
14
|
-
_slack_token:
|
|
15
|
-
_slack_channel:
|
|
16
|
-
_slack_client:
|
|
14
|
+
_slack_token: str | None = None
|
|
15
|
+
_slack_channel: str | None = None
|
|
16
|
+
_slack_client: WebClient | None = None
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def init_slack(token: str, channel: str) -> None:
|
|
@@ -36,10 +36,10 @@ def init_slack(token: str, channel: str) -> None:
|
|
|
36
36
|
|
|
37
37
|
def send_slack_message(
|
|
38
38
|
message: str,
|
|
39
|
-
blocks:
|
|
40
|
-
attachments:
|
|
41
|
-
thread_ts:
|
|
42
|
-
channel:
|
|
39
|
+
blocks: Sequence[dict[str, Any]] | None = None,
|
|
40
|
+
attachments: Sequence[dict[str, Any]] | None = None,
|
|
41
|
+
thread_ts: str | None = None,
|
|
42
|
+
channel: str | None = None,
|
|
43
43
|
):
|
|
44
44
|
"""
|
|
45
45
|
Send a message to a Slack channel.
|
intentkit/utils/tx.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
from typing import Any, Dict, Tuple
|
|
2
|
+
|
|
1
3
|
from pydantic import BaseModel, Field
|
|
2
4
|
from web3 import Web3
|
|
3
5
|
|
|
4
6
|
|
|
5
7
|
class EvmContractWrapper:
|
|
6
|
-
def __init__(
|
|
8
|
+
def __init__(
|
|
9
|
+
self, rpc_url: str, abi: list[dict[str, Any]], tx_data: Dict[str, Any]
|
|
10
|
+
):
|
|
7
11
|
w3 = Web3(Web3.HTTPProvider(rpc_url))
|
|
8
12
|
contract = w3.eth.contract(abi=abi)
|
|
9
13
|
|
|
10
|
-
self.evm_tx = EvmTx(
|
|
14
|
+
self.evm_tx = EvmTx.model_validate(tx_data)
|
|
11
15
|
self.fn, self.fn_args = contract.decode_function_input(self.evm_tx.data)
|
|
12
16
|
|
|
13
17
|
for i, arg in self.fn_args.items():
|
|
@@ -19,19 +23,23 @@ class EvmContractWrapper:
|
|
|
19
23
|
] # Convert list of bytes to list of hex strings
|
|
20
24
|
|
|
21
25
|
@property
|
|
22
|
-
def fn_and_args(self):
|
|
26
|
+
def fn_and_args(self) -> Tuple[Any, Dict[str, Any]]:
|
|
23
27
|
return self.fn, self.fn_args
|
|
24
28
|
|
|
25
29
|
@property
|
|
26
|
-
def dst_addr(self):
|
|
30
|
+
def dst_addr(self) -> str | None:
|
|
27
31
|
return self.evm_tx.to
|
|
28
32
|
|
|
29
33
|
|
|
30
34
|
class EvmTx(BaseModel):
|
|
31
|
-
data: str = Field(None, description="Data of the transaction.")
|
|
32
|
-
to: str
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
data: str | None = Field(None, description="Data of the transaction.")
|
|
36
|
+
to: str | None = Field(
|
|
37
|
+
None, description="Address of the receiver of the transaction."
|
|
38
|
+
)
|
|
39
|
+
from_: str | None = Field(
|
|
40
|
+
None, description="Address of the sender of the transaction."
|
|
41
|
+
)
|
|
42
|
+
value: str | None = Field(None, description="Amount of token to send.")
|
|
35
43
|
gas: int | None = Field(None, description="Gas amount.")
|
|
36
44
|
gasPrice: int | None = Field(None, description="Gas Price.")
|
|
37
45
|
nonce: int | None = Field(None, description="Nonce of transaction.")
|