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
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from langchain.agents.middleware import AgentMiddleware
|
|
8
|
+
from langchain.agents.middleware.summarization import SummarizationMiddleware
|
|
9
|
+
from langchain_core.messages import (
|
|
10
|
+
AIMessage,
|
|
11
|
+
BaseMessage,
|
|
12
|
+
RemoveMessage,
|
|
13
|
+
ToolMessage,
|
|
14
|
+
)
|
|
15
|
+
from langchain_core.messages.utils import count_tokens_approximately, trim_messages
|
|
16
|
+
from langchain_core.tools import BaseTool
|
|
17
|
+
from langgraph.graph.message import REMOVE_ALL_MESSAGES
|
|
18
|
+
from langgraph.runtime import Runtime
|
|
19
|
+
from langgraph.types import StreamWriter
|
|
20
|
+
|
|
21
|
+
from intentkit.abstracts.graph import AgentContext, AgentError, AgentState
|
|
22
|
+
from intentkit.core.credit import skill_cost
|
|
23
|
+
from intentkit.core.prompt import build_system_prompt
|
|
24
|
+
from intentkit.models.credit import CreditAccount, OwnerType
|
|
25
|
+
from intentkit.models.llm import LLMModelInfo, LLMProvider
|
|
26
|
+
from intentkit.models.skill import Skill
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _validate_chat_history(messages: Sequence[BaseMessage]) -> None:
|
|
32
|
+
"""Validate that all tool calls in AIMessages have a corresponding ToolMessage."""
|
|
33
|
+
|
|
34
|
+
all_tool_calls = [
|
|
35
|
+
tool_call
|
|
36
|
+
for message in messages
|
|
37
|
+
if isinstance(message, AIMessage)
|
|
38
|
+
for tool_call in message.tool_calls
|
|
39
|
+
]
|
|
40
|
+
tool_call_ids_with_results = {
|
|
41
|
+
message.tool_call_id for message in messages if isinstance(message, ToolMessage)
|
|
42
|
+
}
|
|
43
|
+
tool_calls_without_results = [
|
|
44
|
+
tool_call
|
|
45
|
+
for tool_call in all_tool_calls
|
|
46
|
+
if tool_call["id"] not in tool_call_ids_with_results
|
|
47
|
+
]
|
|
48
|
+
if not tool_calls_without_results:
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
message = (
|
|
52
|
+
"Found AIMessages with tool_calls that do not have a corresponding ToolMessage. "
|
|
53
|
+
f"Here are the first few of those tool calls: {tool_calls_without_results[:3]}"
|
|
54
|
+
)
|
|
55
|
+
raise ValueError(message)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TrimMessagesMiddleware(AgentMiddleware[AgentState, AgentContext]):
|
|
59
|
+
"""Middleware that trims conversation history before invoking the model."""
|
|
60
|
+
|
|
61
|
+
def __init__(self, *, max_summary_tokens: int) -> None:
|
|
62
|
+
super().__init__()
|
|
63
|
+
self.max_summary_tokens = max_summary_tokens
|
|
64
|
+
|
|
65
|
+
async def abefore_model(
|
|
66
|
+
self, state: AgentState, runtime: Runtime[AgentContext]
|
|
67
|
+
) -> dict[str, Any]:
|
|
68
|
+
del runtime
|
|
69
|
+
messages = state.get("messages")
|
|
70
|
+
context = state.get("context", {})
|
|
71
|
+
if messages is None or not isinstance(messages, list) or len(messages) == 0:
|
|
72
|
+
raise ValueError("Missing required field `messages` in the input.")
|
|
73
|
+
try:
|
|
74
|
+
_validate_chat_history(messages)
|
|
75
|
+
except ValueError as e:
|
|
76
|
+
logger.error(f"Invalid chat history: {e}")
|
|
77
|
+
logger.info(state)
|
|
78
|
+
return {"messages": [RemoveMessage(REMOVE_ALL_MESSAGES)]}
|
|
79
|
+
|
|
80
|
+
trimmed_messages = trim_messages(
|
|
81
|
+
messages,
|
|
82
|
+
strategy="last",
|
|
83
|
+
token_counter=count_tokens_approximately,
|
|
84
|
+
max_tokens=self.max_summary_tokens,
|
|
85
|
+
start_on="human",
|
|
86
|
+
end_on=("human", "tool"),
|
|
87
|
+
)
|
|
88
|
+
if len(trimmed_messages) < len(messages):
|
|
89
|
+
logger.info(f"Trimmed messages: {len(messages)} -> {len(trimmed_messages)}")
|
|
90
|
+
if len(trimmed_messages) <= 3:
|
|
91
|
+
logger.info(f"Too few messages after trim: {len(trimmed_messages)}")
|
|
92
|
+
return {}
|
|
93
|
+
return {
|
|
94
|
+
"messages": [RemoveMessage(REMOVE_ALL_MESSAGES)] + trimmed_messages,
|
|
95
|
+
"context": context,
|
|
96
|
+
}
|
|
97
|
+
return {}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class DynamicPromptMiddleware(AgentMiddleware[AgentState, AgentContext]):
|
|
101
|
+
"""Middleware that builds the system prompt dynamically per request."""
|
|
102
|
+
|
|
103
|
+
def __init__(self, agent, agent_data) -> None:
|
|
104
|
+
super().__init__()
|
|
105
|
+
self.agent = agent
|
|
106
|
+
self.agent_data = agent_data
|
|
107
|
+
|
|
108
|
+
async def awrap_model_call(self, request, handler): # type: ignore[override]
|
|
109
|
+
context = request.runtime.context
|
|
110
|
+
system_prompt = await build_system_prompt(self.agent, self.agent_data, context)
|
|
111
|
+
updated_request = request.override(system_prompt=system_prompt)
|
|
112
|
+
return await handler(updated_request)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ToolBindingMiddleware(AgentMiddleware[AgentState, AgentContext]):
|
|
116
|
+
"""Middleware that selects tools and model parameters based on context."""
|
|
117
|
+
|
|
118
|
+
def __init__(
|
|
119
|
+
self,
|
|
120
|
+
llm_model: LLMModelInfo,
|
|
121
|
+
public_tools: list[BaseTool | dict],
|
|
122
|
+
private_tools: list[BaseTool | dict],
|
|
123
|
+
) -> None:
|
|
124
|
+
super().__init__()
|
|
125
|
+
self.llm_model = llm_model
|
|
126
|
+
self.public_tools = public_tools
|
|
127
|
+
self.private_tools = private_tools
|
|
128
|
+
|
|
129
|
+
async def awrap_model_call(self, request, handler): # type: ignore[override]
|
|
130
|
+
context = request.runtime.context
|
|
131
|
+
|
|
132
|
+
llm_params: dict[str, Any] = {}
|
|
133
|
+
tools: list[BaseTool | dict] = (
|
|
134
|
+
self.private_tools if context.is_private else self.public_tools
|
|
135
|
+
)
|
|
136
|
+
tools = list(
|
|
137
|
+
{
|
|
138
|
+
tool.name if isinstance(tool, BaseTool) else str(tool): tool
|
|
139
|
+
for tool in tools
|
|
140
|
+
}.values()
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if context.search or context.agent.has_search():
|
|
144
|
+
if self.llm_model.info.supports_search:
|
|
145
|
+
tools.append({"type": "web_search"})
|
|
146
|
+
if (
|
|
147
|
+
self.llm_model.info.provider == LLMProvider.OPENAI
|
|
148
|
+
and self.llm_model.model_name == "gpt-5-mini"
|
|
149
|
+
):
|
|
150
|
+
llm_params["reasoning_effort"] = "medium"
|
|
151
|
+
if self.llm_model.info.provider == LLMProvider.XAI:
|
|
152
|
+
llm_params["search_parameters"] = {"mode": "auto"}
|
|
153
|
+
else:
|
|
154
|
+
logger.debug(
|
|
155
|
+
"Search requested but model does not support native search"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
model = await self.llm_model.create_instance(llm_params)
|
|
159
|
+
updated_request = request.override(
|
|
160
|
+
model=model,
|
|
161
|
+
tools=tools,
|
|
162
|
+
model_settings=llm_params,
|
|
163
|
+
)
|
|
164
|
+
return await handler(updated_request)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class CreditCheckMiddleware(AgentMiddleware[AgentState, AgentContext]):
|
|
168
|
+
"""Middleware that validates tool affordability before execution."""
|
|
169
|
+
|
|
170
|
+
def __init__(self) -> None:
|
|
171
|
+
super().__init__()
|
|
172
|
+
self.func_accepts_config = True
|
|
173
|
+
|
|
174
|
+
async def aafter_model(
|
|
175
|
+
self,
|
|
176
|
+
state: AgentState,
|
|
177
|
+
runtime: Runtime[AgentContext],
|
|
178
|
+
*,
|
|
179
|
+
writer: StreamWriter | None = None,
|
|
180
|
+
) -> dict[str, Any]:
|
|
181
|
+
context = runtime.context
|
|
182
|
+
messages = state.get("messages")
|
|
183
|
+
if messages is None or not isinstance(messages, list) or len(messages) == 0:
|
|
184
|
+
raise ValueError("Missing required field `messages` in the input.")
|
|
185
|
+
|
|
186
|
+
payer = context.payer
|
|
187
|
+
if not payer:
|
|
188
|
+
return {}
|
|
189
|
+
|
|
190
|
+
msg = messages[-1]
|
|
191
|
+
agent = context.agent
|
|
192
|
+
account = await CreditAccount.get_or_create(OwnerType.USER, payer)
|
|
193
|
+
if hasattr(msg, "tool_calls") and msg.tool_calls:
|
|
194
|
+
for tool_call in msg.tool_calls:
|
|
195
|
+
skill_meta = await Skill.get(tool_call.get("name"))
|
|
196
|
+
if not skill_meta:
|
|
197
|
+
continue
|
|
198
|
+
skill_cost_info = await skill_cost(skill_meta.name, payer, agent)
|
|
199
|
+
total_paid = skill_cost_info.total_amount
|
|
200
|
+
if not account.has_sufficient_credits(total_paid):
|
|
201
|
+
error_message = (
|
|
202
|
+
"Insufficient credits. Please top up your account. "
|
|
203
|
+
f"You need {total_paid} credits, but you only have {account.balance} credits."
|
|
204
|
+
)
|
|
205
|
+
state_update: dict[str, Any] = {
|
|
206
|
+
"error": AgentError.INSUFFICIENT_CREDITS,
|
|
207
|
+
"messages": [
|
|
208
|
+
RemoveMessage(id=msg.id),
|
|
209
|
+
AIMessage(content=error_message),
|
|
210
|
+
],
|
|
211
|
+
}
|
|
212
|
+
if writer:
|
|
213
|
+
writer(
|
|
214
|
+
{
|
|
215
|
+
"credit_check": {
|
|
216
|
+
"error": AgentError.INSUFFICIENT_CREDITS,
|
|
217
|
+
"message": error_message,
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
return state_update
|
|
222
|
+
return {}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
__all__ = [
|
|
226
|
+
"CreditCheckMiddleware",
|
|
227
|
+
"DynamicPromptMiddleware",
|
|
228
|
+
"SummarizationMiddleware",
|
|
229
|
+
"ToolBindingMiddleware",
|
|
230
|
+
"TrimMessagesMiddleware",
|
|
231
|
+
]
|
intentkit/core/prompt.py
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import re
|
|
2
|
-
from typing import Callable, Optional
|
|
3
2
|
|
|
4
3
|
from eth_utils import is_address
|
|
5
|
-
from langchain_core.messages import BaseMessage
|
|
6
|
-
from langchain_core.prompts import ChatPromptTemplate
|
|
7
|
-
from langgraph.runtime import Runtime
|
|
8
4
|
|
|
9
|
-
from intentkit.abstracts.graph import AgentContext
|
|
5
|
+
from intentkit.abstracts.graph import AgentContext
|
|
10
6
|
from intentkit.config.config import config
|
|
11
7
|
from intentkit.models.agent import Agent
|
|
12
8
|
from intentkit.models.agent_data import AgentData
|
|
13
9
|
from intentkit.models.chat import AuthorType
|
|
14
10
|
from intentkit.models.skill import Skill
|
|
11
|
+
from intentkit.models.user import User
|
|
15
12
|
|
|
16
13
|
# ============================================================================
|
|
17
14
|
# CONSTANTS AND CONFIGURATION
|
|
@@ -34,7 +31,6 @@ user confirmation before broadcasting any approval transactions for security rea
|
|
|
34
31
|
|
|
35
32
|
"""
|
|
36
33
|
|
|
37
|
-
|
|
38
34
|
# ============================================================================
|
|
39
35
|
# CORE PROMPT BUILDING FUNCTIONS
|
|
40
36
|
# ============================================================================
|
|
@@ -110,28 +106,66 @@ def _build_wallet_section(agent: Agent, agent_data: AgentData) -> str:
|
|
|
110
106
|
|
|
111
107
|
if agent_data.evm_wallet_address and network_id != "solana":
|
|
112
108
|
wallet_parts.append(
|
|
113
|
-
f"Your wallet address
|
|
109
|
+
f"Your EVM wallet address is {agent_data.evm_wallet_address}."
|
|
110
|
+
f"You are now in {network_id} network."
|
|
114
111
|
)
|
|
115
112
|
if agent_data.solana_wallet_address and network_id == "solana":
|
|
116
113
|
wallet_parts.append(
|
|
117
|
-
f"Your wallet address
|
|
114
|
+
f"Your Solana wallet address is {agent_data.solana_wallet_address}."
|
|
115
|
+
f"You are now in {network_id} network."
|
|
118
116
|
)
|
|
119
117
|
|
|
118
|
+
# Add CDP skills prompt if CDP skills are enabled
|
|
119
|
+
if agent.skills and "cdp" in agent.skills:
|
|
120
|
+
cdp_config = agent.skills["cdp"]
|
|
121
|
+
if cdp_config and cdp_config.get("enabled") is True:
|
|
122
|
+
# Check if any CDP skills are in public or private state (not disabled)
|
|
123
|
+
states = cdp_config.get("states", {})
|
|
124
|
+
has_enabled_cdp_skills = any(
|
|
125
|
+
state in ["public", "private"] for state in states.values()
|
|
126
|
+
)
|
|
127
|
+
if has_enabled_cdp_skills:
|
|
128
|
+
wallet_parts.append(
|
|
129
|
+
"If a skill input parameter requires a token address but you only have the user-provided token symbol, "
|
|
130
|
+
"and the address cannot be found in the nearby context, you must use the `token_search` skill to query "
|
|
131
|
+
f"the address of that symbol on the current chain ({network_id}) and confirm this address with the user."
|
|
132
|
+
"If the `token_search` skill is not found, remind the user to enable it."
|
|
133
|
+
)
|
|
134
|
+
|
|
120
135
|
return "\n".join(wallet_parts) + ("\n" if wallet_parts else "")
|
|
121
136
|
|
|
122
137
|
|
|
123
|
-
def _build_user_info_section(context: AgentContext) -> str:
|
|
138
|
+
async def _build_user_info_section(context: AgentContext) -> str:
|
|
124
139
|
"""Build user information section when user_id is a valid EVM wallet address."""
|
|
125
140
|
if not context.user_id:
|
|
126
141
|
return ""
|
|
127
142
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
user = await User.get(context.user_id)
|
|
144
|
+
|
|
145
|
+
prompt_array = []
|
|
146
|
+
|
|
147
|
+
evm_wallet_address = ""
|
|
148
|
+
if user and user.evm_wallet_address:
|
|
149
|
+
evm_wallet_address = user.evm_wallet_address
|
|
150
|
+
elif is_address(context.user_id):
|
|
151
|
+
evm_wallet_address = context.user_id
|
|
152
|
+
|
|
153
|
+
if evm_wallet_address:
|
|
154
|
+
prompt_array.append(
|
|
155
|
+
f"The user you are talking to has EVM wallet address: {evm_wallet_address}\n"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
if user:
|
|
159
|
+
if user.email:
|
|
160
|
+
prompt_array.append(f"User Email: {user.email}\n")
|
|
161
|
+
if user.x_username:
|
|
162
|
+
prompt_array.append(f"User X Username: {user.x_username}\n")
|
|
163
|
+
if user.telegram_username:
|
|
164
|
+
prompt_array.append(f"User Telegram Username: {user.telegram_username}\n")
|
|
165
|
+
|
|
166
|
+
if prompt_array:
|
|
167
|
+
prompt_array.append("\n")
|
|
168
|
+
return "## User Info\n\n" + "".join(prompt_array)
|
|
135
169
|
|
|
136
170
|
return ""
|
|
137
171
|
|
|
@@ -202,36 +236,19 @@ def agent_prompt(agent: Agent, agent_data: AgentData) -> str:
|
|
|
202
236
|
|
|
203
237
|
|
|
204
238
|
async def explain_prompt(message: str) -> str:
|
|
205
|
-
""
|
|
206
|
-
Process message to replace @skill:*:* patterns with (call skill xxxxx) format.
|
|
207
|
-
This function is used when admin_llm_skill_control is enabled.
|
|
208
|
-
|
|
209
|
-
Args:
|
|
210
|
-
message (str): The input message to process
|
|
211
|
-
|
|
212
|
-
Returns:
|
|
213
|
-
str: The processed message with @skill patterns replaced
|
|
214
|
-
"""
|
|
215
|
-
# Pattern to match @skill:category:config_name with word boundaries
|
|
216
|
-
pattern = r"\b@skill:([^:]+):([^\s]+)\b"
|
|
239
|
+
pattern = r"@skill:([^:]+):([^\s]+)\b"
|
|
217
240
|
|
|
218
241
|
async def replace_skill_pattern(match):
|
|
219
242
|
category = match.group(1)
|
|
220
243
|
config_name = match.group(2)
|
|
221
244
|
|
|
222
|
-
# Get skill by category and config_name
|
|
223
245
|
skill = await Skill.get_by_config_name(category, config_name)
|
|
224
|
-
|
|
225
246
|
if skill:
|
|
226
247
|
return f"(call skill {skill.name})"
|
|
227
248
|
else:
|
|
228
|
-
# If skill not found, keep original pattern
|
|
229
249
|
return match.group(0)
|
|
230
250
|
|
|
231
|
-
# Find all matches
|
|
232
251
|
matches = list(re.finditer(pattern, message))
|
|
233
|
-
|
|
234
|
-
# Process matches in reverse order to maintain string positions
|
|
235
252
|
result = message
|
|
236
253
|
for match in reversed(matches):
|
|
237
254
|
replacement = await replace_skill_pattern(match)
|
|
@@ -290,7 +307,7 @@ def _build_autonomous_task_prompt(agent: Agent, context: AgentContext) -> str:
|
|
|
290
307
|
return f"{task_info}. "
|
|
291
308
|
|
|
292
309
|
|
|
293
|
-
async def build_entrypoint_prompt(agent: Agent, context: AgentContext) ->
|
|
310
|
+
async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> str | None:
|
|
294
311
|
"""
|
|
295
312
|
Build entrypoint-specific prompt based on context.
|
|
296
313
|
|
|
@@ -303,7 +320,7 @@ async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> Option
|
|
|
303
320
|
context: The agent context containing entrypoint information
|
|
304
321
|
|
|
305
322
|
Returns:
|
|
306
|
-
|
|
323
|
+
str | None: The entrypoint-specific prompt, or None if no entrypoint
|
|
307
324
|
"""
|
|
308
325
|
if not context.entrypoint:
|
|
309
326
|
return None
|
|
@@ -325,10 +342,6 @@ async def build_entrypoint_prompt(agent: Agent, context: AgentContext) -> Option
|
|
|
325
342
|
elif entrypoint == AuthorType.TRIGGER.value:
|
|
326
343
|
entrypoint_prompt = "\n\n" + _build_autonomous_task_prompt(agent, context)
|
|
327
344
|
|
|
328
|
-
# Process with admin LLM skill control if enabled
|
|
329
|
-
if entrypoint_prompt and config.admin_llm_skill_control:
|
|
330
|
-
entrypoint_prompt = await explain_prompt(entrypoint_prompt)
|
|
331
|
-
|
|
332
345
|
return entrypoint_prompt
|
|
333
346
|
|
|
334
347
|
|
|
@@ -348,83 +361,30 @@ def build_internal_info_prompt(context: AgentContext) -> str:
|
|
|
348
361
|
# ============================================================================
|
|
349
362
|
|
|
350
363
|
|
|
351
|
-
def
|
|
352
|
-
|
|
353
|
-
|
|
364
|
+
async def build_system_prompt(
|
|
365
|
+
agent: Agent, agent_data: AgentData, context: AgentContext
|
|
366
|
+
) -> str:
|
|
367
|
+
"""Construct the final system prompt for an agent run."""
|
|
354
368
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
agent's runtime to format prompts for each conversation.
|
|
369
|
+
base_prompt = build_agent_prompt(agent, agent_data)
|
|
370
|
+
final_system_prompt = await explain_prompt(escape_prompt(base_prompt))
|
|
358
371
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
"""
|
|
366
|
-
# Build base prompt using the new function name
|
|
367
|
-
prompt = build_agent_prompt(agent, agent_data)
|
|
368
|
-
escaped_prompt = escape_prompt(prompt)
|
|
369
|
-
|
|
370
|
-
# Process with admin LLM skill control if enabled
|
|
371
|
-
async def get_base_prompt():
|
|
372
|
-
if config.admin_llm_skill_control:
|
|
373
|
-
return await explain_prompt(escaped_prompt)
|
|
374
|
-
return escaped_prompt
|
|
375
|
-
|
|
376
|
-
# Build prompt array
|
|
377
|
-
prompt_array = [
|
|
378
|
-
("placeholder", "{system_prompt}"),
|
|
379
|
-
("placeholder", "{messages}"),
|
|
380
|
-
]
|
|
381
|
-
|
|
382
|
-
if agent.prompt_append:
|
|
383
|
-
# Escape any curly braces in prompt_append
|
|
384
|
-
escaped_append = escape_prompt(agent.prompt_append)
|
|
385
|
-
prompt_array.append(("system", escaped_append))
|
|
386
|
-
|
|
387
|
-
prompt_temp = ChatPromptTemplate.from_messages(prompt_array)
|
|
388
|
-
|
|
389
|
-
async def formatted_prompt(
|
|
390
|
-
state: AgentState, runtime: Runtime[AgentContext]
|
|
391
|
-
) -> list[BaseMessage]:
|
|
392
|
-
# Get base prompt (with potential admin LLM skill control processing)
|
|
393
|
-
final_system_prompt = await get_base_prompt()
|
|
372
|
+
entrypoint_prompt = await build_entrypoint_prompt(agent, context)
|
|
373
|
+
if entrypoint_prompt:
|
|
374
|
+
processed_entrypoint = await explain_prompt(entrypoint_prompt)
|
|
375
|
+
final_system_prompt = (
|
|
376
|
+
f"{final_system_prompt}## Entrypoint rules{processed_entrypoint}\n\n"
|
|
377
|
+
)
|
|
394
378
|
|
|
395
|
-
|
|
379
|
+
user_info = await _build_user_info_section(context)
|
|
380
|
+
if user_info:
|
|
381
|
+
final_system_prompt = f"{final_system_prompt}{user_info}"
|
|
396
382
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if entrypoint_prompt:
|
|
400
|
-
final_system_prompt = (
|
|
401
|
-
f"{final_system_prompt}## Entrypoint rules{entrypoint_prompt}\n\n"
|
|
402
|
-
)
|
|
383
|
+
internal_info = build_internal_info_prompt(context)
|
|
384
|
+
final_system_prompt = f"{final_system_prompt}{internal_info}"
|
|
403
385
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
final_system_prompt = f"{final_system_prompt}{user_info}"
|
|
408
|
-
|
|
409
|
-
# Add internal info
|
|
410
|
-
internal_info = build_internal_info_prompt(context)
|
|
411
|
-
final_system_prompt = f"{final_system_prompt}{internal_info}"
|
|
412
|
-
|
|
413
|
-
# Process prompt_append with admin LLM skill control if needed
|
|
414
|
-
if agent.prompt_append and config.admin_llm_skill_control:
|
|
415
|
-
# Find the system message in prompt_array and process it
|
|
416
|
-
for i, (role, content) in enumerate(prompt_array):
|
|
417
|
-
if role == "system":
|
|
418
|
-
processed_append = await explain_prompt(content)
|
|
419
|
-
prompt_array[i] = ("system", processed_append)
|
|
420
|
-
break
|
|
421
|
-
|
|
422
|
-
system_prompt = [("system", final_system_prompt)]
|
|
423
|
-
return prompt_temp.invoke(
|
|
424
|
-
{
|
|
425
|
-
"messages": state["messages"],
|
|
426
|
-
"system_prompt": system_prompt,
|
|
427
|
-
}
|
|
428
|
-
)
|
|
386
|
+
if agent.prompt_append:
|
|
387
|
+
processed_append = await explain_prompt(agent.prompt_append)
|
|
388
|
+
final_system_prompt = f"{final_system_prompt}{processed_append}"
|
|
429
389
|
|
|
430
|
-
return
|
|
390
|
+
return final_system_prompt
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Core scheduler utilities."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping, MutableMapping
|
|
6
|
+
|
|
7
|
+
from apscheduler.jobstores.base import BaseJobStore
|
|
8
|
+
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
9
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
10
|
+
|
|
11
|
+
from intentkit.core.agent import (
|
|
12
|
+
update_agent_action_cost,
|
|
13
|
+
update_agents_account_snapshot,
|
|
14
|
+
update_agents_statistics,
|
|
15
|
+
)
|
|
16
|
+
from intentkit.core.credit import refill_all_free_credits
|
|
17
|
+
from intentkit.models.agent_data import AgentQuota
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def create_scheduler(
|
|
21
|
+
jobstores: Mapping[str, BaseJobStore]
|
|
22
|
+
| MutableMapping[str, BaseJobStore]
|
|
23
|
+
| None = None,
|
|
24
|
+
) -> AsyncIOScheduler:
|
|
25
|
+
"""Create and configure the APScheduler with all periodic tasks."""
|
|
26
|
+
scheduler = AsyncIOScheduler(jobstores=dict(jobstores or {}))
|
|
27
|
+
|
|
28
|
+
# Reset daily quotas at UTC 00:00
|
|
29
|
+
scheduler.add_job(
|
|
30
|
+
AgentQuota.reset_daily_quotas,
|
|
31
|
+
trigger=CronTrigger(hour=0, minute=0, timezone="UTC"),
|
|
32
|
+
id="reset_daily_quotas",
|
|
33
|
+
name="Reset daily quotas",
|
|
34
|
+
replace_existing=True,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Reset monthly quotas at UTC 00:00 on the first day of each month
|
|
38
|
+
scheduler.add_job(
|
|
39
|
+
AgentQuota.reset_monthly_quotas,
|
|
40
|
+
trigger=CronTrigger(day=1, hour=0, minute=0, timezone="UTC"),
|
|
41
|
+
id="reset_monthly_quotas",
|
|
42
|
+
name="Reset monthly quotas",
|
|
43
|
+
replace_existing=True,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Refill free credits every hour at minute 20
|
|
47
|
+
scheduler.add_job(
|
|
48
|
+
refill_all_free_credits,
|
|
49
|
+
trigger=CronTrigger(minute="20", timezone="UTC"),
|
|
50
|
+
id="refill_free_credits",
|
|
51
|
+
name="Refill free credits",
|
|
52
|
+
replace_existing=True,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Update agent account snapshots hourly
|
|
56
|
+
scheduler.add_job(
|
|
57
|
+
update_agents_account_snapshot,
|
|
58
|
+
trigger=CronTrigger(minute=0, timezone="UTC"),
|
|
59
|
+
id="update_agent_account_snapshot",
|
|
60
|
+
name="Update agent account snapshots",
|
|
61
|
+
replace_existing=True,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Update agent assets daily at UTC midnight
|
|
65
|
+
# This is too expensive to run daily, so it will only be triggered when detail page is visited
|
|
66
|
+
# scheduler.add_job(
|
|
67
|
+
# update_agents_assets,
|
|
68
|
+
# trigger=CronTrigger(hour=0, minute=0, timezone="UTC"),
|
|
69
|
+
# id="update_agent_assets",
|
|
70
|
+
# name="Update agent assets",
|
|
71
|
+
# replace_existing=True,
|
|
72
|
+
# )
|
|
73
|
+
|
|
74
|
+
# Update agent action costs hourly at minute 40
|
|
75
|
+
scheduler.add_job(
|
|
76
|
+
update_agent_action_cost,
|
|
77
|
+
trigger=CronTrigger(minute="40", timezone="UTC"),
|
|
78
|
+
id="update_agent_action_cost",
|
|
79
|
+
name="Update agent action costs",
|
|
80
|
+
replace_existing=True,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Update agent statistics daily at UTC 00:01
|
|
84
|
+
scheduler.add_job(
|
|
85
|
+
update_agents_statistics,
|
|
86
|
+
trigger=CronTrigger(hour=0, minute=1, timezone="UTC"),
|
|
87
|
+
id="update_agent_statistics",
|
|
88
|
+
name="Update agent statistics",
|
|
89
|
+
replace_existing=True,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Run quick account consistency checks every 2 hours at the top of the hour
|
|
93
|
+
# Run quick account consistency checks every 2 hours at the top of the hour
|
|
94
|
+
from intentkit.core.account_checking import run_quick_checks, run_slow_checks
|
|
95
|
+
|
|
96
|
+
async def run_quick_account_checks():
|
|
97
|
+
"""Run quick account consistency checks and send results to Slack."""
|
|
98
|
+
# logger is not defined in this scope, so we use a local logger or print
|
|
99
|
+
# But better to use the one from the module if we move the logger definition up or import it
|
|
100
|
+
import logging
|
|
101
|
+
|
|
102
|
+
logger = logging.getLogger(__name__)
|
|
103
|
+
logger.info("Running scheduled quick account consistency checks")
|
|
104
|
+
try:
|
|
105
|
+
_ = await run_quick_checks()
|
|
106
|
+
logger.info("Completed quick account consistency checks")
|
|
107
|
+
except Exception as e:
|
|
108
|
+
logger.error(f"Error running quick account consistency checks: {e}")
|
|
109
|
+
|
|
110
|
+
async def run_slow_account_checks():
|
|
111
|
+
"""Run slow account consistency checks and send results to Slack."""
|
|
112
|
+
import logging
|
|
113
|
+
|
|
114
|
+
logger = logging.getLogger(__name__)
|
|
115
|
+
logger.info("Running scheduled slow account consistency checks")
|
|
116
|
+
try:
|
|
117
|
+
_ = await run_slow_checks()
|
|
118
|
+
logger.info("Completed slow account consistency checks")
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.error(f"Error running slow account consistency checks: {e}")
|
|
121
|
+
|
|
122
|
+
scheduler.add_job(
|
|
123
|
+
run_quick_account_checks,
|
|
124
|
+
trigger=CronTrigger(
|
|
125
|
+
hour="*/2", minute="30", timezone="UTC"
|
|
126
|
+
), # Run every 2 hours
|
|
127
|
+
id="quick_account_checks",
|
|
128
|
+
name="Quick Account Consistency Checks",
|
|
129
|
+
replace_existing=True,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Run slow account consistency checks once a day at midnight UTC
|
|
133
|
+
scheduler.add_job(
|
|
134
|
+
run_slow_account_checks,
|
|
135
|
+
trigger=CronTrigger(
|
|
136
|
+
hour="0,12", minute="0", timezone="UTC"
|
|
137
|
+
), # Run 2 times a day
|
|
138
|
+
id="slow_account_checks",
|
|
139
|
+
name="Slow Account Consistency Checks",
|
|
140
|
+
replace_existing=True,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return scheduler
|