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/core/agent.py
CHANGED
|
@@ -1,137 +1,92 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import time
|
|
3
|
-
from
|
|
3
|
+
from collections.abc import AsyncGenerator
|
|
4
|
+
from datetime import UTC, datetime, timedelta
|
|
4
5
|
from decimal import Decimal
|
|
5
|
-
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
|
-
from aiogram import Bot
|
|
8
|
-
from aiogram.exceptions import TelegramConflictError, TelegramUnauthorizedError
|
|
9
|
-
from aiogram.utils.token import TokenValidationError
|
|
10
7
|
from sqlalchemy import func, select, text, update
|
|
11
8
|
|
|
12
|
-
from intentkit.
|
|
13
|
-
from intentkit.clients.cdp import get_cdp_client
|
|
9
|
+
from intentkit.clients.cdp import get_wallet_provider
|
|
14
10
|
from intentkit.config.config import config
|
|
15
11
|
from intentkit.models.agent import (
|
|
16
12
|
Agent,
|
|
17
|
-
AgentAutonomous,
|
|
18
13
|
AgentCreate,
|
|
19
|
-
AgentResponse,
|
|
20
14
|
AgentTable,
|
|
21
15
|
AgentUpdate,
|
|
22
16
|
)
|
|
23
|
-
from intentkit.models.agent_data import AgentData,
|
|
24
|
-
from intentkit.models.credit import
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
ThreadSkillDataCreate,
|
|
17
|
+
from intentkit.models.agent_data import AgentData, AgentQuotaTable
|
|
18
|
+
from intentkit.models.credit import (
|
|
19
|
+
CreditAccount,
|
|
20
|
+
CreditEventTable,
|
|
21
|
+
EventType,
|
|
22
|
+
OwnerType,
|
|
23
|
+
UpstreamType,
|
|
31
24
|
)
|
|
25
|
+
from intentkit.models.db import get_session
|
|
32
26
|
from intentkit.utils.error import IntentKitAPIError
|
|
33
27
|
from intentkit.utils.slack_alert import send_slack_message
|
|
34
28
|
|
|
35
29
|
logger = logging.getLogger(__name__)
|
|
36
30
|
|
|
37
31
|
|
|
38
|
-
async def
|
|
39
|
-
agent: Agent,
|
|
32
|
+
async def process_agent_wallet(
|
|
33
|
+
agent: Agent, old_wallet_provider: str | None = None
|
|
40
34
|
) -> AgentData:
|
|
41
|
-
"""Process
|
|
35
|
+
"""Process agent wallet initialization and validation.
|
|
42
36
|
|
|
43
37
|
Args:
|
|
44
38
|
agent: The agent that was created or updated
|
|
45
|
-
|
|
46
|
-
slack_message: Optional custom message for Slack notification
|
|
39
|
+
old_wallet_provider: Previous wallet provider (None, "cdp", or "readonly")
|
|
47
40
|
|
|
48
41
|
Returns:
|
|
49
42
|
AgentData: The processed agent data
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
IntentKitAPIError: If attempting to change between cdp and readonly providers
|
|
50
46
|
"""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
current_wallet_provider = agent.wallet_provider
|
|
48
|
+
|
|
49
|
+
# 1. Check if changing between cdp and readonly (not allowed)
|
|
50
|
+
if (
|
|
51
|
+
old_wallet_provider is not None
|
|
52
|
+
and old_wallet_provider != "none"
|
|
53
|
+
and old_wallet_provider != current_wallet_provider
|
|
54
|
+
):
|
|
55
|
+
raise IntentKitAPIError(
|
|
56
|
+
400,
|
|
57
|
+
"WalletProviderChangeNotAllowed",
|
|
58
|
+
"Cannot change wallet provider between cdp and readonly",
|
|
59
|
+
)
|
|
54
60
|
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
# 2. If wallet provider hasn't changed, return existing agent data
|
|
62
|
+
if (
|
|
63
|
+
old_wallet_provider is not None
|
|
64
|
+
and old_wallet_provider != "none"
|
|
65
|
+
and old_wallet_provider == current_wallet_provider
|
|
66
|
+
):
|
|
67
|
+
return await AgentData.get(agent.id)
|
|
68
|
+
|
|
69
|
+
# 3. For new agents (old_wallet_provider is None), check if wallet already exists
|
|
70
|
+
agent_data = await AgentData.get(agent.id)
|
|
71
|
+
if agent_data.evm_wallet_address:
|
|
72
|
+
return agent_data
|
|
73
|
+
|
|
74
|
+
# 4. Initialize wallet based on provider type
|
|
75
|
+
if config.cdp_api_key_id and current_wallet_provider == "cdp":
|
|
76
|
+
await get_wallet_provider(agent)
|
|
77
|
+
agent_data = await AgentData.get(agent.id)
|
|
78
|
+
elif current_wallet_provider == "readonly":
|
|
58
79
|
agent_data = await AgentData.patch(
|
|
59
80
|
agent.id,
|
|
60
81
|
{
|
|
61
82
|
"evm_wallet_address": agent.readonly_wallet_address,
|
|
62
83
|
},
|
|
63
84
|
)
|
|
64
|
-
else:
|
|
65
|
-
agent_data = await AgentData.get(agent.id)
|
|
66
|
-
|
|
67
|
-
# Send Slack notification
|
|
68
|
-
slack_message = slack_message or ("Agent Created" if is_new else "Agent Updated")
|
|
69
|
-
try:
|
|
70
|
-
_send_agent_notification(agent, agent_data, slack_message)
|
|
71
|
-
except Exception as e:
|
|
72
|
-
logger.error("Failed to send Slack notification: %s", e)
|
|
73
85
|
|
|
74
86
|
return agent_data
|
|
75
87
|
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
agent: AgentUpdate, existing_agent: Optional[Agent], agent_data: AgentData
|
|
79
|
-
) -> AgentData:
|
|
80
|
-
"""Process telegram configuration for an agent.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
agent: The agent with telegram configuration
|
|
84
|
-
existing_agent: The existing agent (if updating)
|
|
85
|
-
agent_data: The agent data to update
|
|
86
|
-
|
|
87
|
-
Returns:
|
|
88
|
-
AgentData: The updated agent data
|
|
89
|
-
"""
|
|
90
|
-
changes = agent.model_dump(exclude_unset=True)
|
|
91
|
-
if not changes.get("telegram_entrypoint_enabled"):
|
|
92
|
-
return agent_data
|
|
93
|
-
|
|
94
|
-
if not changes.get("telegram_config") or not changes.get("telegram_config").get(
|
|
95
|
-
"token"
|
|
96
|
-
):
|
|
97
|
-
return agent_data
|
|
98
|
-
|
|
99
|
-
tg_bot_token = changes.get("telegram_config").get("token")
|
|
100
|
-
|
|
101
|
-
if existing_agent and existing_agent.telegram_config.get("token") == tg_bot_token:
|
|
102
|
-
return agent_data
|
|
103
|
-
|
|
104
|
-
try:
|
|
105
|
-
bot = Bot(token=tg_bot_token)
|
|
106
|
-
bot_info = await bot.get_me()
|
|
107
|
-
agent_data.telegram_id = str(bot_info.id)
|
|
108
|
-
agent_data.telegram_username = bot_info.username
|
|
109
|
-
agent_data.telegram_name = bot_info.first_name
|
|
110
|
-
if bot_info.last_name:
|
|
111
|
-
agent_data.telegram_name = f"{bot_info.first_name} {bot_info.last_name}"
|
|
112
|
-
await agent_data.save()
|
|
113
|
-
try:
|
|
114
|
-
await bot.close()
|
|
115
|
-
except Exception:
|
|
116
|
-
pass
|
|
117
|
-
return agent_data
|
|
118
|
-
except (
|
|
119
|
-
TelegramUnauthorizedError,
|
|
120
|
-
TelegramConflictError,
|
|
121
|
-
TokenValidationError,
|
|
122
|
-
) as req_err:
|
|
123
|
-
logger.error(
|
|
124
|
-
f"Unauthorized err getting telegram bot username with token {tg_bot_token}: {req_err}",
|
|
125
|
-
)
|
|
126
|
-
return agent_data
|
|
127
|
-
except Exception as e:
|
|
128
|
-
logger.error(
|
|
129
|
-
f"Error getting telegram bot username with token {tg_bot_token}: {e}",
|
|
130
|
-
)
|
|
131
|
-
return agent_data
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def _send_agent_notification(agent: Agent, agent_data: AgentData, message: str) -> None:
|
|
89
|
+
def send_agent_notification(agent: Agent, agent_data: AgentData, message: str) -> None:
|
|
135
90
|
"""Send a notification about agent creation or update.
|
|
136
91
|
|
|
137
92
|
Args:
|
|
@@ -202,7 +157,7 @@ def _send_agent_notification(agent: Agent, agent_data: AgentData, message: str)
|
|
|
202
157
|
{
|
|
203
158
|
"title": "Network",
|
|
204
159
|
"short": True,
|
|
205
|
-
"value": agent.network_id or "
|
|
160
|
+
"value": agent.network_id or "Not Set",
|
|
206
161
|
},
|
|
207
162
|
{
|
|
208
163
|
"title": "X Username",
|
|
@@ -237,71 +192,122 @@ def _send_agent_notification(agent: Agent, agent_data: AgentData, message: str)
|
|
|
237
192
|
)
|
|
238
193
|
|
|
239
194
|
|
|
240
|
-
async def
|
|
241
|
-
agent_id: str, agent: AgentUpdate, owner:
|
|
242
|
-
) ->
|
|
243
|
-
"""Override an existing agent.
|
|
195
|
+
async def override_agent(
|
|
196
|
+
agent_id: str, agent: AgentUpdate, owner: str | None = None
|
|
197
|
+
) -> tuple[Agent, AgentData]:
|
|
198
|
+
"""Override an existing agent with new configuration.
|
|
244
199
|
|
|
245
|
-
|
|
200
|
+
This function updates an existing agent with the provided configuration.
|
|
201
|
+
If some fields are not provided, they will be reset to default values.
|
|
246
202
|
|
|
247
203
|
Args:
|
|
248
|
-
agent_id: ID of the agent to
|
|
249
|
-
agent: Agent update configuration
|
|
250
|
-
owner: Optional owner for
|
|
204
|
+
agent_id: ID of the agent to override
|
|
205
|
+
agent: Agent update configuration containing the new settings
|
|
206
|
+
owner: Optional owner for permission validation
|
|
251
207
|
|
|
252
208
|
Returns:
|
|
253
|
-
|
|
209
|
+
tuple[Agent, AgentData]: Updated agent configuration and processed agent data
|
|
254
210
|
|
|
255
211
|
Raises:
|
|
256
|
-
|
|
257
|
-
- 400: Invalid agent ID format
|
|
212
|
+
IntentKitAPIError:
|
|
258
213
|
- 404: Agent not found
|
|
259
214
|
- 403: Permission denied (if owner mismatch)
|
|
260
|
-
-
|
|
215
|
+
- 400: Invalid configuration or wallet provider change
|
|
261
216
|
"""
|
|
262
217
|
existing_agent = await Agent.get(agent_id)
|
|
263
218
|
if not existing_agent:
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
else:
|
|
269
|
-
agent.owner = "system"
|
|
270
|
-
# Check for existing agent by upstream_id, forward compatibility, raise error after 3.0
|
|
271
|
-
existing = await agent.get_by_upstream_id()
|
|
272
|
-
if existing:
|
|
273
|
-
agent_data = await AgentData.get(existing.id)
|
|
274
|
-
agent_response = await AgentResponse.from_agent(existing, agent_data)
|
|
275
|
-
return agent_response
|
|
276
|
-
|
|
277
|
-
# Create new agent
|
|
278
|
-
latest_agent = await agent.create()
|
|
279
|
-
# Process common post-creation actions
|
|
280
|
-
agent_data = await _process_agent_post_actions(
|
|
281
|
-
latest_agent, True, "Agent Created"
|
|
219
|
+
raise IntentKitAPIError(
|
|
220
|
+
status_code=404,
|
|
221
|
+
key="AgentNotFound",
|
|
222
|
+
message=f"Agent with ID '{agent_id}' not found",
|
|
282
223
|
)
|
|
283
|
-
agent_data = await _process_telegram_config(input, None, agent_data)
|
|
284
|
-
agent_response = await AgentResponse.from_agent(latest_agent, agent_data)
|
|
285
|
-
|
|
286
|
-
return agent_response
|
|
287
|
-
|
|
288
224
|
if owner and owner != existing_agent.owner:
|
|
289
|
-
raise IntentKitAPIError(403, "
|
|
225
|
+
raise IntentKitAPIError(403, "Forbidden", "forbidden")
|
|
290
226
|
|
|
291
227
|
# Update agent
|
|
292
228
|
latest_agent = await agent.override(agent_id)
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
agent_data = await _process_agent_post_actions(
|
|
296
|
-
latest_agent, False, "Agent Overridden"
|
|
229
|
+
agent_data = await process_agent_wallet(
|
|
230
|
+
latest_agent, existing_agent.wallet_provider
|
|
297
231
|
)
|
|
298
|
-
|
|
299
|
-
|
|
232
|
+
send_agent_notification(latest_agent, agent_data, "Agent Overridden Deployed")
|
|
233
|
+
|
|
234
|
+
return latest_agent, agent_data
|
|
235
|
+
|
|
300
236
|
|
|
301
|
-
|
|
237
|
+
async def create_agent(agent: AgentCreate) -> tuple[Agent, AgentData]:
|
|
238
|
+
"""Create a new agent with the provided configuration.
|
|
302
239
|
|
|
240
|
+
This function creates a new agent instance with the given configuration,
|
|
241
|
+
initializes its wallet, and sends a notification about the creation.
|
|
303
242
|
|
|
304
|
-
|
|
243
|
+
Args:
|
|
244
|
+
agent: Agent creation configuration containing all necessary settings
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
tuple[Agent, AgentData]: Created agent configuration and processed agent data
|
|
248
|
+
|
|
249
|
+
Raises:
|
|
250
|
+
IntentKitAPIError:
|
|
251
|
+
- 400: Agent with upstream ID already exists or invalid configuration
|
|
252
|
+
- 500: Database error or wallet initialization failure
|
|
253
|
+
"""
|
|
254
|
+
if not agent.owner:
|
|
255
|
+
agent.owner = "system"
|
|
256
|
+
# Check for existing agent by upstream_id, forward compatibility, raise error after 3.0
|
|
257
|
+
existing = await agent.get_by_upstream_id()
|
|
258
|
+
if existing:
|
|
259
|
+
raise IntentKitAPIError(
|
|
260
|
+
status_code=400,
|
|
261
|
+
key="BadRequest",
|
|
262
|
+
message="Agent with this upstream ID already exists",
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# Create new agent
|
|
266
|
+
latest_agent = await agent.create()
|
|
267
|
+
agent_data = await process_agent_wallet(latest_agent)
|
|
268
|
+
send_agent_notification(latest_agent, agent_data, "Agent Deployed")
|
|
269
|
+
|
|
270
|
+
return latest_agent, agent_data
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
async def deploy_agent(
|
|
274
|
+
agent_id: str, agent: AgentUpdate, owner: str | None = None
|
|
275
|
+
) -> tuple[Agent, AgentData]:
|
|
276
|
+
"""Deploy an agent by first attempting to override, then creating if not found.
|
|
277
|
+
|
|
278
|
+
This function first tries to override an existing agent. If the agent is not found
|
|
279
|
+
(404 error), it will create a new agent instead.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
agent_id: ID of the agent to deploy
|
|
283
|
+
agent: Agent configuration data
|
|
284
|
+
owner: Optional owner for the agent
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
tuple[Agent, AgentData]: Deployed agent configuration and processed agent data
|
|
288
|
+
|
|
289
|
+
Raises:
|
|
290
|
+
IntentKitAPIError:
|
|
291
|
+
- 400: Invalid agent configuration or upstream ID conflict
|
|
292
|
+
- 403: Permission denied (if owner mismatch)
|
|
293
|
+
- 500: Database error
|
|
294
|
+
"""
|
|
295
|
+
try:
|
|
296
|
+
# First try to override the existing agent
|
|
297
|
+
return await override_agent(agent_id, agent, owner)
|
|
298
|
+
except IntentKitAPIError as e:
|
|
299
|
+
# If agent not found (404), create a new one
|
|
300
|
+
if e.status_code == 404:
|
|
301
|
+
new_agent = AgentCreate.model_validate(agent)
|
|
302
|
+
new_agent.id = agent_id
|
|
303
|
+
new_agent.owner = owner
|
|
304
|
+
return await create_agent(new_agent)
|
|
305
|
+
else:
|
|
306
|
+
# Re-raise other errors
|
|
307
|
+
raise
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
async def agent_action_cost(agent_id: str) -> dict[str, Decimal]:
|
|
305
311
|
"""
|
|
306
312
|
Calculate various action cost metrics for an agent based on past three days of credit events.
|
|
307
313
|
|
|
@@ -317,7 +323,7 @@ async def agent_action_cost(agent_id: str) -> Dict[str, Decimal]:
|
|
|
317
323
|
agent_id: ID of the agent
|
|
318
324
|
|
|
319
325
|
Returns:
|
|
320
|
-
|
|
326
|
+
dict[str, Decimal]: Dictionary containing all calculated cost metrics
|
|
321
327
|
"""
|
|
322
328
|
start_time = time.time()
|
|
323
329
|
default_value = Decimal("0")
|
|
@@ -330,7 +336,7 @@ async def agent_action_cost(agent_id: str) -> Dict[str, Decimal]:
|
|
|
330
336
|
|
|
331
337
|
async with get_session() as session:
|
|
332
338
|
# Calculate the date 3 days ago from now
|
|
333
|
-
three_days_ago = datetime.now(
|
|
339
|
+
three_days_ago = datetime.now(UTC) - timedelta(days=3)
|
|
334
340
|
|
|
335
341
|
# First, count the number of distinct start_message_ids to determine if we have enough data
|
|
336
342
|
count_query = select(
|
|
@@ -478,183 +484,31 @@ async def agent_action_cost(agent_id: str) -> Dict[str, Decimal]:
|
|
|
478
484
|
return result
|
|
479
485
|
|
|
480
486
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
skill-related data for both agents and threads.
|
|
486
|
-
"""
|
|
487
|
-
|
|
488
|
-
@staticmethod
|
|
489
|
-
def get_system_config(key: str) -> Any:
|
|
490
|
-
# TODO: maybe need a whitelist here
|
|
491
|
-
if hasattr(config, key):
|
|
492
|
-
return getattr(config, key)
|
|
493
|
-
return None
|
|
494
|
-
|
|
495
|
-
@staticmethod
|
|
496
|
-
async def get_agent_config(agent_id: str) -> Optional[Agent]:
|
|
497
|
-
return await Agent.get(agent_id)
|
|
498
|
-
|
|
499
|
-
@staticmethod
|
|
500
|
-
async def get_agent_data(agent_id: str) -> AgentData:
|
|
501
|
-
return await AgentData.get(agent_id)
|
|
502
|
-
|
|
503
|
-
@staticmethod
|
|
504
|
-
async def set_agent_data(agent_id: str, data: Dict) -> AgentData:
|
|
505
|
-
return await AgentData.patch(agent_id, data)
|
|
506
|
-
|
|
507
|
-
@staticmethod
|
|
508
|
-
async def get_agent_quota(agent_id: str) -> AgentQuota:
|
|
509
|
-
return await AgentQuota.get(agent_id)
|
|
510
|
-
|
|
511
|
-
@staticmethod
|
|
512
|
-
async def get_agent_skill_data(
|
|
513
|
-
agent_id: str, skill: str, key: str
|
|
514
|
-
) -> Optional[Dict[str, Any]]:
|
|
515
|
-
"""Get skill data for an agent.
|
|
516
|
-
|
|
517
|
-
Args:
|
|
518
|
-
agent_id: ID of the agent
|
|
519
|
-
skill: Name of the skill
|
|
520
|
-
key: Data key
|
|
521
|
-
|
|
522
|
-
Returns:
|
|
523
|
-
Dictionary containing the skill data if found, None otherwise
|
|
524
|
-
"""
|
|
525
|
-
return await AgentSkillData.get(agent_id, skill, key)
|
|
526
|
-
|
|
527
|
-
@staticmethod
|
|
528
|
-
async def save_agent_skill_data(
|
|
529
|
-
agent_id: str, skill: str, key: str, data: Dict[str, Any]
|
|
530
|
-
) -> None:
|
|
531
|
-
"""Save or update skill data for an agent.
|
|
532
|
-
|
|
533
|
-
Args:
|
|
534
|
-
agent_id: ID of the agent
|
|
535
|
-
skill: Name of the skill
|
|
536
|
-
key: Data key
|
|
537
|
-
data: JSON data to store
|
|
538
|
-
"""
|
|
539
|
-
skill_data = AgentSkillDataCreate(
|
|
540
|
-
agent_id=agent_id,
|
|
541
|
-
skill=skill,
|
|
542
|
-
key=key,
|
|
543
|
-
data=data,
|
|
544
|
-
)
|
|
545
|
-
await skill_data.save()
|
|
546
|
-
|
|
547
|
-
@staticmethod
|
|
548
|
-
async def delete_agent_skill_data(agent_id: str, skill: str, key: str) -> None:
|
|
549
|
-
"""Delete skill data for an agent.
|
|
550
|
-
|
|
551
|
-
Args:
|
|
552
|
-
agent_id: ID of the agent
|
|
553
|
-
skill: Name of the skill
|
|
554
|
-
key: Data key
|
|
555
|
-
"""
|
|
556
|
-
await AgentSkillData.delete(agent_id, skill, key)
|
|
557
|
-
|
|
558
|
-
@staticmethod
|
|
559
|
-
async def get_thread_skill_data(
|
|
560
|
-
thread_id: str, skill: str, key: str
|
|
561
|
-
) -> Optional[Dict[str, Any]]:
|
|
562
|
-
"""Get skill data for a thread.
|
|
563
|
-
|
|
564
|
-
Args:
|
|
565
|
-
thread_id: ID of the thread
|
|
566
|
-
skill: Name of the skill
|
|
567
|
-
key: Data key
|
|
568
|
-
|
|
569
|
-
Returns:
|
|
570
|
-
Dictionary containing the skill data if found, None otherwise
|
|
571
|
-
"""
|
|
572
|
-
return await ThreadSkillData.get(thread_id, skill, key)
|
|
573
|
-
|
|
574
|
-
@staticmethod
|
|
575
|
-
async def save_thread_skill_data(
|
|
576
|
-
thread_id: str,
|
|
577
|
-
agent_id: str,
|
|
578
|
-
skill: str,
|
|
579
|
-
key: str,
|
|
580
|
-
data: Dict[str, Any],
|
|
581
|
-
) -> None:
|
|
582
|
-
"""Save or update skill data for a thread.
|
|
583
|
-
|
|
584
|
-
Args:
|
|
585
|
-
thread_id: ID of the thread
|
|
586
|
-
agent_id: ID of the agent that owns this thread
|
|
587
|
-
skill: Name of the skill
|
|
588
|
-
key: Data key
|
|
589
|
-
data: JSON data to store
|
|
590
|
-
"""
|
|
591
|
-
skill_data = ThreadSkillDataCreate(
|
|
592
|
-
thread_id=thread_id,
|
|
593
|
-
agent_id=agent_id,
|
|
594
|
-
skill=skill,
|
|
595
|
-
key=key,
|
|
596
|
-
data=data,
|
|
597
|
-
)
|
|
598
|
-
await skill_data.save()
|
|
599
|
-
|
|
600
|
-
@staticmethod
|
|
601
|
-
async def list_autonomous_tasks(agent_id: str) -> List[AgentAutonomous]:
|
|
602
|
-
"""List all autonomous tasks for an agent.
|
|
603
|
-
|
|
604
|
-
Args:
|
|
605
|
-
agent_id: ID of the agent
|
|
487
|
+
async def _iterate_agent_id_batches(
|
|
488
|
+
batch_size: int = 100,
|
|
489
|
+
) -> AsyncGenerator[list[str], None]:
|
|
490
|
+
"""Yield agent IDs in ascending batches to limit memory usage."""
|
|
606
491
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
@staticmethod
|
|
613
|
-
async def add_autonomous_task(
|
|
614
|
-
agent_id: str, task: AgentAutonomous
|
|
615
|
-
) -> AgentAutonomous:
|
|
616
|
-
"""Add a new autonomous task to an agent.
|
|
617
|
-
|
|
618
|
-
Args:
|
|
619
|
-
agent_id: ID of the agent
|
|
620
|
-
task: Autonomous task configuration
|
|
621
|
-
|
|
622
|
-
Returns:
|
|
623
|
-
AgentAutonomous: The created task
|
|
624
|
-
"""
|
|
625
|
-
return await add_autonomous_task(agent_id, task)
|
|
626
|
-
|
|
627
|
-
@staticmethod
|
|
628
|
-
async def delete_autonomous_task(agent_id: str, task_id: str) -> None:
|
|
629
|
-
"""Delete an autonomous task from an agent.
|
|
630
|
-
|
|
631
|
-
Args:
|
|
632
|
-
agent_id: ID of the agent
|
|
633
|
-
task_id: ID of the task to delete
|
|
634
|
-
"""
|
|
635
|
-
await delete_autonomous_task(agent_id, task_id)
|
|
636
|
-
|
|
637
|
-
@staticmethod
|
|
638
|
-
async def update_autonomous_task(
|
|
639
|
-
agent_id: str, task_id: str, task_updates: dict
|
|
640
|
-
) -> AgentAutonomous:
|
|
641
|
-
"""Update an autonomous task for an agent.
|
|
492
|
+
last_id: str | None = None
|
|
493
|
+
while True:
|
|
494
|
+
async with get_session() as session:
|
|
495
|
+
query = select(AgentTable.id).order_by(AgentTable.id)
|
|
642
496
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
task_id: ID of the task to update
|
|
646
|
-
task_updates: Dictionary containing fields to update
|
|
497
|
+
if last_id:
|
|
498
|
+
query = query.where(AgentTable.id > last_id)
|
|
647
499
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
return await update_autonomous_task(agent_id, task_id, task_updates)
|
|
500
|
+
query = query.limit(batch_size)
|
|
501
|
+
result = await session.execute(query)
|
|
502
|
+
agent_ids = [row[0] for row in result]
|
|
652
503
|
|
|
504
|
+
if not agent_ids:
|
|
505
|
+
break
|
|
653
506
|
|
|
654
|
-
|
|
507
|
+
yield agent_ids
|
|
508
|
+
last_id = agent_ids[-1]
|
|
655
509
|
|
|
656
510
|
|
|
657
|
-
async def update_agent_action_cost():
|
|
511
|
+
async def update_agent_action_cost(batch_size: int = 100) -> None:
|
|
658
512
|
"""
|
|
659
513
|
Update action costs for all agents.
|
|
660
514
|
|
|
@@ -671,42 +525,20 @@ async def update_agent_action_cost():
|
|
|
671
525
|
"""
|
|
672
526
|
logger.info("Starting update of agent average action costs")
|
|
673
527
|
start_time = time.time()
|
|
674
|
-
batch_size = 100
|
|
675
|
-
last_id = None
|
|
676
528
|
total_updated = 0
|
|
677
529
|
|
|
678
|
-
|
|
679
|
-
# Get a batch of agent IDs ordered by ID
|
|
680
|
-
async with get_session() as session:
|
|
681
|
-
query = select(AgentTable.id).order_by(AgentTable.id)
|
|
682
|
-
|
|
683
|
-
# Apply pagination if we have a last_id from previous batch
|
|
684
|
-
if last_id:
|
|
685
|
-
query = query.where(AgentTable.id > last_id)
|
|
686
|
-
|
|
687
|
-
query = query.limit(batch_size)
|
|
688
|
-
result = await session.execute(query)
|
|
689
|
-
agent_ids = [row[0] for row in result]
|
|
690
|
-
|
|
691
|
-
# If no more agents, we're done
|
|
692
|
-
if not agent_ids:
|
|
693
|
-
break
|
|
694
|
-
|
|
695
|
-
# Update last_id for next batch
|
|
696
|
-
last_id = agent_ids[-1]
|
|
697
|
-
|
|
698
|
-
# Process this batch of agents
|
|
530
|
+
async for agent_ids in _iterate_agent_id_batches(batch_size):
|
|
699
531
|
logger.info(
|
|
700
|
-
|
|
532
|
+
"Processing batch of %s agents starting with ID %s",
|
|
533
|
+
len(agent_ids),
|
|
534
|
+
agent_ids[0],
|
|
701
535
|
)
|
|
702
536
|
batch_start_time = time.time()
|
|
703
537
|
|
|
704
538
|
for agent_id in agent_ids:
|
|
705
539
|
try:
|
|
706
|
-
# Calculate action costs for this agent
|
|
707
540
|
costs = await agent_action_cost(agent_id)
|
|
708
541
|
|
|
709
|
-
# Update the agent's quota record
|
|
710
542
|
async with get_session() as session:
|
|
711
543
|
update_stmt = (
|
|
712
544
|
update(AgentQuotaTable)
|
|
@@ -724,203 +556,186 @@ async def update_agent_action_cost():
|
|
|
724
556
|
await session.commit()
|
|
725
557
|
|
|
726
558
|
total_updated += 1
|
|
727
|
-
except Exception as e:
|
|
559
|
+
except Exception as e: # pragma: no cover - log path only
|
|
728
560
|
logger.error(
|
|
729
|
-
|
|
561
|
+
"Error updating action costs for agent %s: %s", agent_id, str(e)
|
|
730
562
|
)
|
|
731
563
|
|
|
732
564
|
batch_time = time.time() - batch_start_time
|
|
733
|
-
logger.info(
|
|
565
|
+
logger.info("Completed batch in %.3fs", batch_time)
|
|
734
566
|
|
|
735
567
|
total_time = time.time() - start_time
|
|
736
568
|
logger.info(
|
|
737
|
-
|
|
569
|
+
"Finished updating action costs for %s agents in %.3fs",
|
|
570
|
+
total_updated,
|
|
571
|
+
total_time,
|
|
738
572
|
)
|
|
739
573
|
|
|
740
574
|
|
|
741
|
-
async def
|
|
742
|
-
"""
|
|
743
|
-
List all autonomous tasks for an agent.
|
|
744
|
-
|
|
745
|
-
Args:
|
|
746
|
-
agent_id: ID of the agent
|
|
575
|
+
async def update_agents_account_snapshot(batch_size: int = 100) -> None:
|
|
576
|
+
"""Refresh the cached credit account snapshot for every agent."""
|
|
747
577
|
|
|
748
|
-
|
|
749
|
-
|
|
578
|
+
logger.info("Starting update of agent account snapshots")
|
|
579
|
+
start_time = time.time()
|
|
580
|
+
total_updated = 0
|
|
750
581
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
raise IntentKitAPIError(
|
|
757
|
-
400, "AgentNotFound", f"Agent with ID {agent_id} does not exist."
|
|
582
|
+
async for agent_ids in _iterate_agent_id_batches(batch_size):
|
|
583
|
+
logger.info(
|
|
584
|
+
"Processing snapshot batch of %s agents starting with ID %s",
|
|
585
|
+
len(agent_ids),
|
|
586
|
+
agent_ids[0],
|
|
758
587
|
)
|
|
588
|
+
batch_start_time = time.time()
|
|
759
589
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
590
|
+
for agent_id in agent_ids:
|
|
591
|
+
try:
|
|
592
|
+
async with get_session() as session:
|
|
593
|
+
account = await CreditAccount.get_or_create_in_session(
|
|
594
|
+
session, OwnerType.AGENT, agent_id
|
|
595
|
+
)
|
|
596
|
+
await session.execute(
|
|
597
|
+
update(AgentTable)
|
|
598
|
+
.where(AgentTable.id == agent_id)
|
|
599
|
+
.values(
|
|
600
|
+
account_snapshot=account.model_dump(mode="json"),
|
|
601
|
+
)
|
|
602
|
+
)
|
|
603
|
+
await session.commit()
|
|
765
604
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
605
|
+
total_updated += 1
|
|
606
|
+
except Exception as exc: # pragma: no cover - log path only
|
|
607
|
+
logger.error(
|
|
608
|
+
"Error updating account snapshot for agent %s: %s",
|
|
609
|
+
agent_id,
|
|
610
|
+
exc,
|
|
611
|
+
)
|
|
769
612
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
task: Autonomous task configuration (id will be generated if not provided)
|
|
613
|
+
batch_time = time.time() - batch_start_time
|
|
614
|
+
logger.info("Completed snapshot batch in %.3fs", batch_time)
|
|
773
615
|
|
|
774
|
-
|
|
775
|
-
|
|
616
|
+
total_time = time.time() - start_time
|
|
617
|
+
logger.info(
|
|
618
|
+
"Finished updating account snapshots for %s agents in %.3fs",
|
|
619
|
+
total_updated,
|
|
620
|
+
total_time,
|
|
621
|
+
)
|
|
776
622
|
|
|
777
|
-
Raises:
|
|
778
|
-
IntentKitAPIError: If agent is not found
|
|
779
|
-
"""
|
|
780
|
-
agent = await Agent.get(agent_id)
|
|
781
|
-
if not agent:
|
|
782
|
-
raise IntentKitAPIError(
|
|
783
|
-
400, "AgentNotFound", f"Agent with ID {agent_id} does not exist."
|
|
784
|
-
)
|
|
785
623
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
if not isinstance(current_tasks, list):
|
|
789
|
-
current_tasks = []
|
|
624
|
+
async def update_agents_assets(batch_size: int = 100) -> None:
|
|
625
|
+
"""Refresh cached asset information for all agents."""
|
|
790
626
|
|
|
791
|
-
|
|
792
|
-
current_tasks.append(task)
|
|
627
|
+
from intentkit.core.asset import agent_asset
|
|
793
628
|
|
|
794
|
-
|
|
795
|
-
|
|
629
|
+
logger.info("Starting update of agent assets")
|
|
630
|
+
start_time = time.time()
|
|
631
|
+
total_updated = 0
|
|
796
632
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
.values(autonomous=serializable_tasks)
|
|
633
|
+
async for agent_ids in _iterate_agent_id_batches(batch_size):
|
|
634
|
+
logger.info(
|
|
635
|
+
"Processing asset batch of %s agents starting with ID %s",
|
|
636
|
+
len(agent_ids),
|
|
637
|
+
agent_ids[0],
|
|
803
638
|
)
|
|
804
|
-
|
|
805
|
-
await session.commit()
|
|
806
|
-
|
|
807
|
-
logger.info(f"Added autonomous task {task.id} to agent {agent_id}")
|
|
808
|
-
return task
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
async def delete_autonomous_task(agent_id: str, task_id: str) -> None:
|
|
812
|
-
"""
|
|
813
|
-
Delete an autonomous task from an agent.
|
|
639
|
+
batch_start_time = time.time()
|
|
814
640
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
641
|
+
for agent_id in agent_ids:
|
|
642
|
+
try:
|
|
643
|
+
assets = await agent_asset(agent_id)
|
|
644
|
+
except IntentKitAPIError as exc: # pragma: no cover - log path only
|
|
645
|
+
logger.warning(
|
|
646
|
+
"Skipping asset update for agent %s due to API error: %s",
|
|
647
|
+
agent_id,
|
|
648
|
+
exc,
|
|
649
|
+
)
|
|
650
|
+
continue
|
|
651
|
+
except Exception as exc: # pragma: no cover - log path only
|
|
652
|
+
logger.error("Error retrieving assets for agent %s: %s", agent_id, exc)
|
|
653
|
+
continue
|
|
818
654
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
655
|
+
try:
|
|
656
|
+
async with get_session() as session:
|
|
657
|
+
await session.execute(
|
|
658
|
+
update(AgentTable)
|
|
659
|
+
.where(AgentTable.id == agent_id)
|
|
660
|
+
.values(assets=assets.model_dump(mode="json"))
|
|
661
|
+
)
|
|
662
|
+
await session.commit()
|
|
827
663
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
# Find and remove the task
|
|
834
|
-
task_found = False
|
|
835
|
-
updated_tasks = []
|
|
836
|
-
for task_data in current_tasks:
|
|
837
|
-
if task_data.id == task_id:
|
|
838
|
-
task_found = True
|
|
839
|
-
continue
|
|
840
|
-
updated_tasks.append(task_data)
|
|
841
|
-
|
|
842
|
-
if not task_found:
|
|
843
|
-
raise IntentKitAPIError(
|
|
844
|
-
404, "TaskNotFound", f"Autonomous task with ID {task_id} not found."
|
|
845
|
-
)
|
|
664
|
+
total_updated += 1
|
|
665
|
+
except Exception as exc: # pragma: no cover - log path only
|
|
666
|
+
logger.error(
|
|
667
|
+
"Error updating asset cache for agent %s: %s", agent_id, exc
|
|
668
|
+
)
|
|
846
669
|
|
|
847
|
-
|
|
848
|
-
|
|
670
|
+
batch_time = time.time() - batch_start_time
|
|
671
|
+
logger.info("Completed asset batch in %.3fs", batch_time)
|
|
849
672
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
)
|
|
857
|
-
await session.execute(update_stmt)
|
|
858
|
-
await session.commit()
|
|
673
|
+
total_time = time.time() - start_time
|
|
674
|
+
logger.info(
|
|
675
|
+
"Finished updating assets for %s agents in %.3fs",
|
|
676
|
+
total_updated,
|
|
677
|
+
total_time,
|
|
678
|
+
)
|
|
859
679
|
|
|
860
|
-
logger.info(f"Deleted autonomous task {task_id} from agent {agent_id}")
|
|
861
680
|
|
|
681
|
+
async def update_agents_statistics(
|
|
682
|
+
*, end_time: datetime | None = None, batch_size: int = 100
|
|
683
|
+
) -> None:
|
|
684
|
+
"""Refresh cached statistics for every agent."""
|
|
862
685
|
|
|
863
|
-
|
|
864
|
-
agent_id: str, task_id: str, task_updates: dict
|
|
865
|
-
) -> AgentAutonomous:
|
|
866
|
-
"""
|
|
867
|
-
Update an autonomous task for an agent.
|
|
686
|
+
from intentkit.core.statistics import get_agent_statistics
|
|
868
687
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
688
|
+
if end_time is None:
|
|
689
|
+
end_time = datetime.now(UTC)
|
|
690
|
+
elif end_time.tzinfo is None:
|
|
691
|
+
end_time = end_time.replace(tzinfo=UTC)
|
|
692
|
+
else:
|
|
693
|
+
end_time = end_time.astimezone(UTC)
|
|
873
694
|
|
|
874
|
-
|
|
875
|
-
|
|
695
|
+
logger.info("Starting update of agent statistics using end_time %s", end_time)
|
|
696
|
+
start_time = time.time()
|
|
697
|
+
total_updated = 0
|
|
876
698
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
raise IntentKitAPIError(
|
|
883
|
-
400, "AgentNotFound", f"Agent with ID {agent_id} does not exist."
|
|
699
|
+
async for agent_ids in _iterate_agent_id_batches(batch_size):
|
|
700
|
+
logger.info(
|
|
701
|
+
"Processing statistics batch of %s agents starting with ID %s",
|
|
702
|
+
len(agent_ids),
|
|
703
|
+
agent_ids[0],
|
|
884
704
|
)
|
|
705
|
+
batch_start_time = time.time()
|
|
885
706
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
for task_data in current_tasks:
|
|
895
|
-
if task_data.id == task_id:
|
|
896
|
-
task_found = True
|
|
897
|
-
# Create a dictionary with current task data
|
|
898
|
-
task_dict = task_data.model_dump()
|
|
899
|
-
# Update with provided fields
|
|
900
|
-
task_dict.update(task_updates)
|
|
901
|
-
# Create new AgentAutonomous instance
|
|
902
|
-
updated_task = AgentAutonomous.model_validate(task_dict)
|
|
903
|
-
updated_tasks.append(updated_task)
|
|
904
|
-
else:
|
|
905
|
-
updated_tasks.append(task_data)
|
|
707
|
+
for agent_id in agent_ids:
|
|
708
|
+
try:
|
|
709
|
+
statistics = await get_agent_statistics(agent_id, end_time=end_time)
|
|
710
|
+
except Exception as exc: # pragma: no cover - log path only
|
|
711
|
+
logger.error(
|
|
712
|
+
"Error computing statistics for agent %s: %s", agent_id, exc
|
|
713
|
+
)
|
|
714
|
+
continue
|
|
906
715
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
716
|
+
try:
|
|
717
|
+
async with get_session() as session:
|
|
718
|
+
await session.execute(
|
|
719
|
+
update(AgentTable)
|
|
720
|
+
.where(AgentTable.id == agent_id)
|
|
721
|
+
.values(statistics=statistics.model_dump(mode="json"))
|
|
722
|
+
)
|
|
723
|
+
await session.commit()
|
|
911
724
|
|
|
912
|
-
|
|
913
|
-
|
|
725
|
+
total_updated += 1
|
|
726
|
+
except Exception as exc: # pragma: no cover - log path only
|
|
727
|
+
logger.error(
|
|
728
|
+
"Error updating statistics cache for agent %s: %s",
|
|
729
|
+
agent_id,
|
|
730
|
+
exc,
|
|
731
|
+
)
|
|
914
732
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
update_stmt = (
|
|
918
|
-
update(AgentTable)
|
|
919
|
-
.where(AgentTable.id == agent_id)
|
|
920
|
-
.values(autonomous=serializable_tasks)
|
|
921
|
-
)
|
|
922
|
-
await session.execute(update_stmt)
|
|
923
|
-
await session.commit()
|
|
733
|
+
batch_time = time.time() - batch_start_time
|
|
734
|
+
logger.info("Completed statistics batch in %.3fs", batch_time)
|
|
924
735
|
|
|
925
|
-
|
|
926
|
-
|
|
736
|
+
total_time = time.time() - start_time
|
|
737
|
+
logger.info(
|
|
738
|
+
"Finished updating statistics for %s agents in %.3fs",
|
|
739
|
+
total_updated,
|
|
740
|
+
total_time,
|
|
741
|
+
)
|