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/node.py
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import Any, Sequence
|
|
3
|
-
|
|
4
|
-
from langchain_core.language_models import LanguageModelLike
|
|
5
|
-
from langchain_core.messages import (
|
|
6
|
-
AIMessage,
|
|
7
|
-
AnyMessage,
|
|
8
|
-
BaseMessage,
|
|
9
|
-
HumanMessage,
|
|
10
|
-
RemoveMessage,
|
|
11
|
-
ToolMessage,
|
|
12
|
-
)
|
|
13
|
-
from langchain_core.messages.utils import count_tokens_approximately, trim_messages
|
|
14
|
-
from langgraph.graph.message import REMOVE_ALL_MESSAGES
|
|
15
|
-
from langgraph.runtime import get_runtime
|
|
16
|
-
from langgraph.utils.runnable import RunnableCallable
|
|
17
|
-
from langmem.short_term.summarization import (
|
|
18
|
-
DEFAULT_EXISTING_SUMMARY_PROMPT,
|
|
19
|
-
DEFAULT_FINAL_SUMMARY_PROMPT,
|
|
20
|
-
DEFAULT_INITIAL_SUMMARY_PROMPT,
|
|
21
|
-
SummarizationResult,
|
|
22
|
-
asummarize_messages,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
from intentkit.abstracts.graph import AgentContext, AgentError, AgentState
|
|
26
|
-
from intentkit.core.credit import skill_cost
|
|
27
|
-
from intentkit.models.agent import Agent
|
|
28
|
-
from intentkit.models.credit import CreditAccount, OwnerType
|
|
29
|
-
from intentkit.models.skill import Skill
|
|
30
|
-
|
|
31
|
-
logger = logging.getLogger(__name__)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _validate_chat_history(
|
|
35
|
-
messages: Sequence[BaseMessage],
|
|
36
|
-
) -> None:
|
|
37
|
-
"""Validate that all tool calls in AIMessages have a corresponding ToolMessage."""
|
|
38
|
-
all_tool_calls = [
|
|
39
|
-
tool_call
|
|
40
|
-
for message in messages
|
|
41
|
-
if isinstance(message, AIMessage)
|
|
42
|
-
for tool_call in message.tool_calls
|
|
43
|
-
]
|
|
44
|
-
tool_call_ids_with_results = {
|
|
45
|
-
message.tool_call_id for message in messages if isinstance(message, ToolMessage)
|
|
46
|
-
}
|
|
47
|
-
tool_calls_without_results = [
|
|
48
|
-
tool_call
|
|
49
|
-
for tool_call in all_tool_calls
|
|
50
|
-
if tool_call["id"] not in tool_call_ids_with_results
|
|
51
|
-
]
|
|
52
|
-
if not tool_calls_without_results:
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
message = "Found AIMessages with tool_calls that do not have a corresponding ToolMessage. "
|
|
56
|
-
f"Here are the first few of those tool calls: {tool_calls_without_results[:3]}"
|
|
57
|
-
raise ValueError(message)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class PreModelNode(RunnableCallable):
|
|
61
|
-
"""LangGraph node that run before the LLM is called."""
|
|
62
|
-
|
|
63
|
-
def __init__(
|
|
64
|
-
self,
|
|
65
|
-
*,
|
|
66
|
-
model: LanguageModelLike,
|
|
67
|
-
short_term_memory_strategy: str,
|
|
68
|
-
max_tokens: int,
|
|
69
|
-
max_summary_tokens: int = 1024,
|
|
70
|
-
) -> None:
|
|
71
|
-
super().__init__(self._func, self._afunc, name="pre_model_node", trace=False)
|
|
72
|
-
self.model = model
|
|
73
|
-
self.short_term_memory_strategy = short_term_memory_strategy
|
|
74
|
-
self.max_tokens = max_tokens
|
|
75
|
-
self.max_tokens_before_summary = max_tokens
|
|
76
|
-
self.max_summary_tokens = max_summary_tokens
|
|
77
|
-
self.token_counter = count_tokens_approximately
|
|
78
|
-
self.initial_summary_prompt = DEFAULT_INITIAL_SUMMARY_PROMPT
|
|
79
|
-
self.existing_summary_prompt = DEFAULT_EXISTING_SUMMARY_PROMPT
|
|
80
|
-
self.final_prompt = DEFAULT_FINAL_SUMMARY_PROMPT
|
|
81
|
-
self.func_accepts_config = True
|
|
82
|
-
|
|
83
|
-
def _parse_input(
|
|
84
|
-
self, input: AgentState
|
|
85
|
-
) -> tuple[list[AnyMessage], dict[str, Any]]:
|
|
86
|
-
messages = input.get("messages")
|
|
87
|
-
context = input.get("context", {})
|
|
88
|
-
if messages is None or not isinstance(messages, list) or len(messages) == 0:
|
|
89
|
-
raise ValueError("Missing required field `messages` in the input.")
|
|
90
|
-
return messages, context
|
|
91
|
-
|
|
92
|
-
# overwrite old messages if summarization is used
|
|
93
|
-
def _prepare_state_update(
|
|
94
|
-
self, context: dict[str, Any], summarization_result: SummarizationResult
|
|
95
|
-
) -> dict[str, Any]:
|
|
96
|
-
state_update = {
|
|
97
|
-
"messages": [RemoveMessage(REMOVE_ALL_MESSAGES)]
|
|
98
|
-
+ summarization_result.messages
|
|
99
|
-
}
|
|
100
|
-
if summarization_result.running_summary:
|
|
101
|
-
state_update["context"] = {
|
|
102
|
-
**context,
|
|
103
|
-
"running_summary": summarization_result.running_summary,
|
|
104
|
-
}
|
|
105
|
-
return state_update
|
|
106
|
-
|
|
107
|
-
def _func(self, AgentState) -> dict[str, Any]:
|
|
108
|
-
raise NotImplementedError("Not implemented yet")
|
|
109
|
-
|
|
110
|
-
async def _afunc(self, input: AgentState) -> dict[str, Any]:
|
|
111
|
-
messages, context = self._parse_input(input)
|
|
112
|
-
try:
|
|
113
|
-
_validate_chat_history(messages)
|
|
114
|
-
except ValueError as e:
|
|
115
|
-
logger.error(f"Invalid chat history: {e}")
|
|
116
|
-
logger.info(input)
|
|
117
|
-
# delete all messages
|
|
118
|
-
return {"messages": [RemoveMessage(REMOVE_ALL_MESSAGES)]}
|
|
119
|
-
if self.short_term_memory_strategy == "trim":
|
|
120
|
-
trimmed_messages = trim_messages(
|
|
121
|
-
messages,
|
|
122
|
-
strategy="last",
|
|
123
|
-
token_counter=self.token_counter,
|
|
124
|
-
max_tokens=self.max_summary_tokens,
|
|
125
|
-
start_on="human",
|
|
126
|
-
end_on=("human", "tool"),
|
|
127
|
-
)
|
|
128
|
-
if len(trimmed_messages) < len(messages):
|
|
129
|
-
logger.info(
|
|
130
|
-
f"Trimmed messages: {len(messages)} -> {len(trimmed_messages)}"
|
|
131
|
-
)
|
|
132
|
-
if len(trimmed_messages) <= 3:
|
|
133
|
-
logger.info(f"Too few messages after trim: {len(trimmed_messages)}")
|
|
134
|
-
return {}
|
|
135
|
-
return {
|
|
136
|
-
"messages": [RemoveMessage(REMOVE_ALL_MESSAGES)] + trimmed_messages,
|
|
137
|
-
}
|
|
138
|
-
else:
|
|
139
|
-
return {}
|
|
140
|
-
if self.short_term_memory_strategy == "summarize":
|
|
141
|
-
# if last message is not human message, skip summarize
|
|
142
|
-
if not isinstance(messages[-1], HumanMessage):
|
|
143
|
-
return {}
|
|
144
|
-
# summarization is from outside, sometimes it is not stable, so we need to try-catch it
|
|
145
|
-
try:
|
|
146
|
-
summarization_result = await asummarize_messages(
|
|
147
|
-
messages,
|
|
148
|
-
running_summary=context.get("running_summary"),
|
|
149
|
-
model=self.model,
|
|
150
|
-
max_tokens=self.max_tokens,
|
|
151
|
-
max_tokens_before_summary=self.max_tokens_before_summary,
|
|
152
|
-
max_summary_tokens=self.max_summary_tokens,
|
|
153
|
-
token_counter=self.token_counter,
|
|
154
|
-
initial_summary_prompt=self.initial_summary_prompt,
|
|
155
|
-
existing_summary_prompt=self.existing_summary_prompt,
|
|
156
|
-
final_prompt=self.final_prompt,
|
|
157
|
-
)
|
|
158
|
-
if summarization_result.running_summary:
|
|
159
|
-
logger.debug(f"Summarization result: {summarization_result}")
|
|
160
|
-
else:
|
|
161
|
-
logger.debug("Summarization not run")
|
|
162
|
-
return self._prepare_state_update(context, summarization_result)
|
|
163
|
-
except ValueError as e:
|
|
164
|
-
logger.error(f"Invalid chat history: {e}")
|
|
165
|
-
logger.info(input)
|
|
166
|
-
# delete all messages
|
|
167
|
-
return {"messages": [RemoveMessage(REMOVE_ALL_MESSAGES)]}
|
|
168
|
-
raise ValueError(
|
|
169
|
-
f"Invalid short_term_memory_strategy: {self.short_term_memory_strategy}"
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
class PostModelNode(RunnableCallable):
|
|
174
|
-
def __init__(self) -> None:
|
|
175
|
-
super().__init__(self._func, self._afunc, name="post_model_node", trace=False)
|
|
176
|
-
self.func_accepts_config = True
|
|
177
|
-
|
|
178
|
-
def _func(self, input: AgentState) -> dict[str, Any]:
|
|
179
|
-
raise NotImplementedError("Not implemented yet")
|
|
180
|
-
|
|
181
|
-
async def _afunc(self, input: AgentState) -> dict[str, Any]:
|
|
182
|
-
runtime = get_runtime(AgentContext)
|
|
183
|
-
context = runtime.context
|
|
184
|
-
logger.debug(f"Running PostModelNode, input: {input}, context: {context}")
|
|
185
|
-
state_update = {}
|
|
186
|
-
messages = input.get("messages")
|
|
187
|
-
if messages is None or not isinstance(messages, list) or len(messages) == 0:
|
|
188
|
-
raise ValueError("Missing required field `messages` in the input.")
|
|
189
|
-
payer = context.payer
|
|
190
|
-
if not payer:
|
|
191
|
-
return state_update
|
|
192
|
-
logger.debug(f"last: {messages[-1]}")
|
|
193
|
-
msg = messages[-1]
|
|
194
|
-
agent_id = context.agent_id
|
|
195
|
-
agent = await Agent.get(agent_id)
|
|
196
|
-
account = await CreditAccount.get_or_create(OwnerType.USER, payer)
|
|
197
|
-
if hasattr(msg, "tool_calls") and msg.tool_calls:
|
|
198
|
-
for tool_call in msg.tool_calls:
|
|
199
|
-
skill_meta = await Skill.get(tool_call.get("name"))
|
|
200
|
-
if skill_meta:
|
|
201
|
-
skill_cost_info = await skill_cost(skill_meta.name, payer, agent)
|
|
202
|
-
total_paid = skill_cost_info.total_amount
|
|
203
|
-
if not account.has_sufficient_credits(total_paid):
|
|
204
|
-
state_update["error"] = AgentError.INSUFFICIENT_CREDITS
|
|
205
|
-
state_update["messages"] = [RemoveMessage(id=msg.id)]
|
|
206
|
-
state_update["messages"].append(
|
|
207
|
-
AIMessage(
|
|
208
|
-
content=f"Insufficient credits. Please top up your account. You need {total_paid} credits, but you only have {account.balance} credits.",
|
|
209
|
-
)
|
|
210
|
-
)
|
|
211
|
-
return state_update
|
|
212
|
-
return state_update
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
post_model_node = PostModelNode()
|
intentkit/models/conversation.py
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
"""Conversation models for agent generator.
|
|
2
|
-
|
|
3
|
-
This module provides models for tracking conversation history and projects
|
|
4
|
-
related to agent generation sessions.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from datetime import datetime
|
|
8
|
-
from typing import Annotated, List, Optional
|
|
9
|
-
|
|
10
|
-
from epyxid import XID
|
|
11
|
-
from intentkit.models.base import Base
|
|
12
|
-
from intentkit.models.db import get_session
|
|
13
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
14
|
-
from sqlalchemy import (
|
|
15
|
-
Column,
|
|
16
|
-
DateTime,
|
|
17
|
-
Index,
|
|
18
|
-
String,
|
|
19
|
-
Text,
|
|
20
|
-
desc,
|
|
21
|
-
func,
|
|
22
|
-
select,
|
|
23
|
-
)
|
|
24
|
-
from sqlalchemy.dialects.postgresql import JSON, JSONB
|
|
25
|
-
from sqlalchemy.ext.asyncio import AsyncSession
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class ConversationProjectTable(Base):
|
|
29
|
-
"""Conversation project database table model."""
|
|
30
|
-
|
|
31
|
-
__tablename__ = "generator_conversation_projects"
|
|
32
|
-
__table_args__ = (
|
|
33
|
-
Index("ix_generator_conversation_projects_user_id", "user_id"),
|
|
34
|
-
Index("ix_generator_conversation_projects_created_at", "created_at"),
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
id = Column(
|
|
38
|
-
String,
|
|
39
|
-
primary_key=True,
|
|
40
|
-
)
|
|
41
|
-
user_id = Column(
|
|
42
|
-
String,
|
|
43
|
-
nullable=True,
|
|
44
|
-
)
|
|
45
|
-
created_at = Column(
|
|
46
|
-
DateTime(timezone=True),
|
|
47
|
-
nullable=False,
|
|
48
|
-
server_default=func.now(),
|
|
49
|
-
)
|
|
50
|
-
last_activity = Column(
|
|
51
|
-
DateTime(timezone=True),
|
|
52
|
-
nullable=False,
|
|
53
|
-
server_default=func.now(),
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
class ConversationMessageTable(Base):
|
|
58
|
-
"""Conversation message database table model."""
|
|
59
|
-
|
|
60
|
-
__tablename__ = "generator_conversation_messages"
|
|
61
|
-
__table_args__ = (
|
|
62
|
-
Index("ix_generator_conversation_messages_project_id", "project_id"),
|
|
63
|
-
Index("ix_generator_conversation_messages_created_at", "created_at"),
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
id = Column(
|
|
67
|
-
String,
|
|
68
|
-
primary_key=True,
|
|
69
|
-
)
|
|
70
|
-
project_id = Column(
|
|
71
|
-
String,
|
|
72
|
-
nullable=False,
|
|
73
|
-
)
|
|
74
|
-
role = Column(
|
|
75
|
-
String,
|
|
76
|
-
nullable=False,
|
|
77
|
-
)
|
|
78
|
-
content = Column(
|
|
79
|
-
Text,
|
|
80
|
-
nullable=False,
|
|
81
|
-
)
|
|
82
|
-
message_metadata = Column(
|
|
83
|
-
JSON().with_variant(JSONB(), "postgresql"),
|
|
84
|
-
nullable=True,
|
|
85
|
-
)
|
|
86
|
-
created_at = Column(
|
|
87
|
-
DateTime(timezone=True),
|
|
88
|
-
nullable=False,
|
|
89
|
-
server_default=func.now(),
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
class ConversationProjectCreate(BaseModel):
|
|
94
|
-
"""Base model for creating conversation projects."""
|
|
95
|
-
|
|
96
|
-
model_config = ConfigDict(from_attributes=True)
|
|
97
|
-
|
|
98
|
-
id: Annotated[
|
|
99
|
-
str,
|
|
100
|
-
Field(
|
|
101
|
-
default_factory=lambda: str(XID()),
|
|
102
|
-
description="Unique identifier for the conversation project",
|
|
103
|
-
),
|
|
104
|
-
]
|
|
105
|
-
user_id: Annotated[
|
|
106
|
-
Optional[str],
|
|
107
|
-
Field(None, description="User ID associated with this project"),
|
|
108
|
-
]
|
|
109
|
-
|
|
110
|
-
async def save_in_session(self, db: AsyncSession) -> "ConversationProject":
|
|
111
|
-
"""Save the conversation project in the given database session."""
|
|
112
|
-
db_project = ConversationProjectTable(
|
|
113
|
-
id=self.id,
|
|
114
|
-
user_id=self.user_id,
|
|
115
|
-
)
|
|
116
|
-
db.add(db_project)
|
|
117
|
-
await db.flush()
|
|
118
|
-
await db.refresh(db_project)
|
|
119
|
-
return ConversationProject.model_validate(db_project)
|
|
120
|
-
|
|
121
|
-
async def save(self) -> "ConversationProject":
|
|
122
|
-
"""Save the conversation project to the database."""
|
|
123
|
-
async with get_session() as db:
|
|
124
|
-
result = await self.save_in_session(db)
|
|
125
|
-
await db.commit()
|
|
126
|
-
return result
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
class ConversationProject(ConversationProjectCreate):
|
|
130
|
-
"""Conversation project model with all fields including server-generated ones."""
|
|
131
|
-
|
|
132
|
-
model_config = ConfigDict(
|
|
133
|
-
from_attributes=True,
|
|
134
|
-
json_encoders={
|
|
135
|
-
datetime: lambda v: v.isoformat(timespec="milliseconds"),
|
|
136
|
-
},
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
created_at: Annotated[
|
|
140
|
-
datetime, Field(description="Timestamp when this project was created")
|
|
141
|
-
]
|
|
142
|
-
last_activity: Annotated[
|
|
143
|
-
datetime, Field(description="Timestamp of last activity in this project")
|
|
144
|
-
]
|
|
145
|
-
|
|
146
|
-
@classmethod
|
|
147
|
-
async def get(cls, project_id: str) -> Optional["ConversationProject"]:
|
|
148
|
-
"""Get a conversation project by ID."""
|
|
149
|
-
async with get_session() as db:
|
|
150
|
-
result = await db.execute(
|
|
151
|
-
select(ConversationProjectTable).where(
|
|
152
|
-
ConversationProjectTable.id == project_id
|
|
153
|
-
)
|
|
154
|
-
)
|
|
155
|
-
project = result.scalar_one_or_none()
|
|
156
|
-
if project:
|
|
157
|
-
return cls.model_validate(project)
|
|
158
|
-
return None
|
|
159
|
-
|
|
160
|
-
async def update_activity(self) -> "ConversationProject":
|
|
161
|
-
"""Update the last activity timestamp for this project."""
|
|
162
|
-
async with get_session() as db:
|
|
163
|
-
from sqlalchemy import update
|
|
164
|
-
|
|
165
|
-
await db.execute(
|
|
166
|
-
update(ConversationProjectTable)
|
|
167
|
-
.where(ConversationProjectTable.id == self.id)
|
|
168
|
-
.values(last_activity=func.now())
|
|
169
|
-
)
|
|
170
|
-
await db.commit()
|
|
171
|
-
# Refresh the object
|
|
172
|
-
result = await db.execute(
|
|
173
|
-
select(ConversationProjectTable).where(
|
|
174
|
-
ConversationProjectTable.id == self.id
|
|
175
|
-
)
|
|
176
|
-
)
|
|
177
|
-
project = result.scalar_one()
|
|
178
|
-
return ConversationProject.model_validate(project)
|
|
179
|
-
|
|
180
|
-
@classmethod
|
|
181
|
-
async def get_by_user(
|
|
182
|
-
cls, user_id: Optional[str] = None, limit: int = 50
|
|
183
|
-
) -> List["ConversationProject"]:
|
|
184
|
-
"""Get conversation projects by user ID."""
|
|
185
|
-
async with get_session() as db:
|
|
186
|
-
query = select(ConversationProjectTable).order_by(
|
|
187
|
-
desc(ConversationProjectTable.last_activity)
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
if user_id is not None:
|
|
191
|
-
query = query.where(ConversationProjectTable.user_id == user_id)
|
|
192
|
-
|
|
193
|
-
query = query.limit(limit)
|
|
194
|
-
|
|
195
|
-
result = await db.execute(query)
|
|
196
|
-
projects = result.scalars().all()
|
|
197
|
-
return [cls.model_validate(project) for project in projects]
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
class ConversationMessageCreate(BaseModel):
|
|
201
|
-
"""Base model for creating conversation messages."""
|
|
202
|
-
|
|
203
|
-
model_config = ConfigDict(from_attributes=True)
|
|
204
|
-
|
|
205
|
-
id: Annotated[
|
|
206
|
-
str,
|
|
207
|
-
Field(
|
|
208
|
-
default_factory=lambda: str(XID()),
|
|
209
|
-
description="Unique identifier for the conversation message",
|
|
210
|
-
),
|
|
211
|
-
]
|
|
212
|
-
project_id: Annotated[str, Field(description="Project ID this message belongs to")]
|
|
213
|
-
role: Annotated[str, Field(description="Role of the message sender")]
|
|
214
|
-
content: Annotated[str, Field(description="Content of the message")]
|
|
215
|
-
message_metadata: Annotated[
|
|
216
|
-
Optional[dict],
|
|
217
|
-
Field(None, description="Additional metadata for the message"),
|
|
218
|
-
]
|
|
219
|
-
|
|
220
|
-
async def save_in_session(self, db: AsyncSession) -> "ConversationMessage":
|
|
221
|
-
"""Save the conversation message in the given database session."""
|
|
222
|
-
db_message = ConversationMessageTable(
|
|
223
|
-
id=self.id,
|
|
224
|
-
project_id=self.project_id,
|
|
225
|
-
role=self.role,
|
|
226
|
-
content=self.content,
|
|
227
|
-
message_metadata=self.message_metadata,
|
|
228
|
-
)
|
|
229
|
-
db.add(db_message)
|
|
230
|
-
await db.flush()
|
|
231
|
-
await db.refresh(db_message)
|
|
232
|
-
return ConversationMessage.model_validate(db_message)
|
|
233
|
-
|
|
234
|
-
async def save(self) -> "ConversationMessage":
|
|
235
|
-
"""Save the conversation message to the database."""
|
|
236
|
-
async with get_session() as db:
|
|
237
|
-
result = await self.save_in_session(db)
|
|
238
|
-
await db.commit()
|
|
239
|
-
return result
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
class ConversationMessage(ConversationMessageCreate):
|
|
243
|
-
"""Conversation message model with all fields including server-generated ones."""
|
|
244
|
-
|
|
245
|
-
model_config = ConfigDict(
|
|
246
|
-
from_attributes=True,
|
|
247
|
-
json_encoders={
|
|
248
|
-
datetime: lambda v: v.isoformat(timespec="milliseconds"),
|
|
249
|
-
},
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
created_at: Annotated[
|
|
253
|
-
datetime, Field(description="Timestamp when this message was created")
|
|
254
|
-
]
|
|
255
|
-
|
|
256
|
-
@classmethod
|
|
257
|
-
async def get_by_project(
|
|
258
|
-
cls, project_id: str, user_id: Optional[str] = None
|
|
259
|
-
) -> List["ConversationMessage"]:
|
|
260
|
-
"""Get conversation messages for a project."""
|
|
261
|
-
async with get_session() as db:
|
|
262
|
-
# First check if project exists and user has access
|
|
263
|
-
project_query = select(ConversationProjectTable).where(
|
|
264
|
-
ConversationProjectTable.id == project_id
|
|
265
|
-
)
|
|
266
|
-
if user_id is not None:
|
|
267
|
-
project_query = project_query.where(
|
|
268
|
-
ConversationProjectTable.user_id == user_id
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
project_result = await db.execute(project_query)
|
|
272
|
-
project = project_result.scalar_one_or_none()
|
|
273
|
-
|
|
274
|
-
if not project:
|
|
275
|
-
return []
|
|
276
|
-
|
|
277
|
-
# Get messages for the project
|
|
278
|
-
messages_query = (
|
|
279
|
-
select(ConversationMessageTable)
|
|
280
|
-
.where(ConversationMessageTable.project_id == project_id)
|
|
281
|
-
.order_by(ConversationMessageTable.created_at)
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
result = await db.execute(messages_query)
|
|
285
|
-
messages = result.scalars().all()
|
|
286
|
-
return [cls.model_validate(message) for message in messages]
|