intentkit 0.6.13.dev2__py3-none-any.whl → 0.8.17__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.
Potentially problematic release.
This version of intentkit might be problematic. Click here for more details.
- intentkit/__init__.py +1 -1
- intentkit/abstracts/agent.py +4 -5
- intentkit/abstracts/engine.py +5 -5
- intentkit/abstracts/graph.py +14 -7
- intentkit/abstracts/skill.py +6 -144
- intentkit/abstracts/twitter.py +4 -5
- intentkit/clients/__init__.py +5 -2
- intentkit/clients/cdp.py +101 -141
- intentkit/clients/twitter.py +83 -62
- intentkit/clients/web3.py +29 -0
- intentkit/config/config.py +8 -5
- intentkit/core/agent.py +472 -195
- intentkit/core/asset.py +253 -0
- intentkit/core/chat.py +51 -0
- intentkit/core/client.py +1 -1
- intentkit/core/credit.py +460 -130
- intentkit/core/engine.py +262 -233
- intentkit/core/node.py +15 -16
- intentkit/core/prompt.py +62 -28
- intentkit/core/scheduler.py +92 -0
- intentkit/core/statistics.py +168 -0
- intentkit/models/agent.py +1096 -949
- intentkit/models/agent_data.py +68 -38
- intentkit/models/agent_public.json +98 -0
- intentkit/models/agent_schema.json +54 -439
- intentkit/models/app_setting.py +96 -33
- intentkit/models/chat.py +74 -27
- intentkit/models/conversation.py +8 -8
- intentkit/models/credit.py +362 -74
- intentkit/models/db.py +26 -8
- intentkit/models/db_mig.py +2 -2
- intentkit/models/llm.csv +28 -0
- intentkit/models/llm.py +185 -350
- intentkit/models/redis.py +6 -4
- intentkit/models/skill.py +186 -72
- intentkit/models/skills.csv +174 -0
- intentkit/models/user.py +82 -24
- 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 +248 -85
- 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 +5 -5
- intentkit/skills/casino/README.md +254 -0
- intentkit/skills/casino/__init__.py +86 -0
- intentkit/skills/casino/base.py +17 -0
- intentkit/skills/casino/casino.png +0 -0
- intentkit/skills/casino/deck_draw.py +127 -0
- intentkit/skills/casino/deck_shuffle.py +118 -0
- intentkit/skills/casino/dice_roll.py +100 -0
- intentkit/skills/casino/schema.json +77 -0
- intentkit/skills/casino/utils.py +107 -0
- 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 +11 -25
- 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 +11 -21
- 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/README.md +154 -0
- intentkit/skills/dexscreener/__init__.py +97 -93
- intentkit/skills/dexscreener/base.py +125 -133
- intentkit/skills/dexscreener/get_pair_info.py +158 -0
- intentkit/skills/dexscreener/get_token_pairs.py +165 -0
- intentkit/skills/dexscreener/get_tokens_info.py +212 -0
- intentkit/skills/dexscreener/model/search_token_response.py +80 -82
- intentkit/skills/dexscreener/schema.json +91 -48
- intentkit/skills/dexscreener/search_token.py +182 -321
- intentkit/skills/dexscreener/utils.py +420 -0
- 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 +50 -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/README.md +11 -5
- intentkit/skills/firecrawl/__init__.py +5 -18
- intentkit/skills/firecrawl/base.py +4 -11
- 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 +6 -8
- intentkit/skills/firecrawl/scrape.py +150 -40
- 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 +12 -13
- intentkit/skills/heurist/image_generation_arthemy_comics.py +12 -13
- intentkit/skills/heurist/image_generation_arthemy_real.py +12 -13
- intentkit/skills/heurist/image_generation_braindance.py +12 -13
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +12 -13
- intentkit/skills/heurist/image_generation_flux_1_dev.py +12 -13
- intentkit/skills/heurist/image_generation_sdxl.py +12 -13
- 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 +1 -7
- intentkit/skills/lifi/schema.json +17 -8
- intentkit/skills/lifi/token_execute.py +36 -30
- 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 +23 -0
- intentkit/skills/openai/__init__.py +17 -18
- intentkit/skills/openai/base.py +10 -14
- intentkit/skills/openai/dalle_image_generation.py +3 -8
- intentkit/skills/openai/gpt_avatar_generator.py +102 -0
- intentkit/skills/openai/gpt_image_generation.py +4 -8
- intentkit/skills/openai/gpt_image_mini_generator.py +91 -0
- intentkit/skills/openai/gpt_image_to_image.py +4 -8
- 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 +40 -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 +9 -13
- intentkit/skills/supabase/delete_data.py +5 -6
- intentkit/skills/supabase/fetch_data.py +13 -14
- intentkit/skills/supabase/insert_data.py +5 -6
- intentkit/skills/supabase/invoke_function.py +7 -8
- intentkit/skills/supabase/schema.json +2 -3
- intentkit/skills/supabase/update_data.py +7 -8
- intentkit/skills/supabase/upsert_data.py +5 -6
- 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 +23 -35
- intentkit/skills/twitter/follow_user.py +3 -7
- intentkit/skills/twitter/get_mentions.py +6 -13
- intentkit/skills/twitter/get_timeline.py +5 -13
- intentkit/skills/twitter/get_user_by_username.py +3 -7
- intentkit/skills/twitter/get_user_tweets.py +6 -14
- intentkit/skills/twitter/like_tweet.py +3 -7
- intentkit/skills/twitter/post_tweet.py +23 -12
- intentkit/skills/twitter/reply_tweet.py +21 -12
- intentkit/skills/twitter/retweet.py +3 -7
- intentkit/skills/twitter/schema.json +1 -0
- intentkit/skills/twitter/search_tweets.py +5 -13
- 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 +9 -9
- 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 +61 -0
- intentkit/skills/x402/ask_agent.py +98 -0
- intentkit/skills/x402/base.py +99 -0
- intentkit/skills/x402/http_request.py +117 -0
- intentkit/skills/x402/schema.json +45 -0
- intentkit/skills/x402/x402.webp +0 -0
- intentkit/skills/xmtp/__init__.py +4 -15
- intentkit/skills/xmtp/base.py +61 -2
- intentkit/skills/xmtp/price.py +18 -13
- intentkit/skills/xmtp/schema.json +69 -71
- intentkit/skills/xmtp/swap.py +22 -25
- intentkit/skills/xmtp/transfer.py +71 -32
- intentkit/utils/chain.py +3 -3
- intentkit/utils/error.py +14 -1
- intentkit/utils/logging.py +2 -4
- intentkit/utils/s3.py +59 -7
- intentkit/utils/schema.py +100 -0
- intentkit/utils/slack_alert.py +7 -8
- {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/METADATA +14 -16
- intentkit-0.8.17.dist-info/RECORD +466 -0
- intentkit/abstracts/exception.py +0 -9
- intentkit/core/skill.py +0 -200
- 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.6.13.dev2.dist-info/RECORD +0 -409
- {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/WHEEL +0 -0
- {intentkit-0.6.13.dev2.dist-info → intentkit-0.8.17.dist-info}/licenses/LICENSE +0 -0
intentkit/models/app_setting.py
CHANGED
|
@@ -1,16 +1,42 @@
|
|
|
1
|
-
import
|
|
2
|
-
from datetime import
|
|
1
|
+
import time
|
|
2
|
+
from datetime import UTC, datetime
|
|
3
3
|
from decimal import ROUND_HALF_UP, Decimal
|
|
4
|
-
from
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Annotated, Any
|
|
5
6
|
|
|
6
7
|
from intentkit.models.base import Base
|
|
7
8
|
from intentkit.models.db import get_session
|
|
8
|
-
from intentkit.models.redis import get_redis
|
|
9
9
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
10
10
|
from sqlalchemy import Column, DateTime, String, func, select
|
|
11
11
|
from sqlalchemy.dialects.postgresql import JSON, JSONB
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
class SystemMessageType(str, Enum):
|
|
15
|
+
"""Type of system message."""
|
|
16
|
+
|
|
17
|
+
SERVICE_FEE_ERROR = "service_fee_error"
|
|
18
|
+
DAILY_USAGE_LIMIT_EXCEEDED = "daily_usage_limit_exceeded"
|
|
19
|
+
INSUFFICIENT_BALANCE = "insufficient_balance"
|
|
20
|
+
AGENT_INTERNAL_ERROR = "agent_internal_error"
|
|
21
|
+
STEP_LIMIT_EXCEEDED = "step_limit_exceeded"
|
|
22
|
+
SKILL_INTERRUPTED = "skill_interrupted"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Default system messages
|
|
26
|
+
DEFAULT_SYSTEM_MESSAGES = {
|
|
27
|
+
"service_fee_error": "Please lower this Agent's service fee to meet the allowed maximum.",
|
|
28
|
+
"daily_usage_limit_exceeded": "This Agent has reached its free daily usage limit. Add credits to continue, or wait until tomorrow.",
|
|
29
|
+
"insufficient_balance": "You don't have enough credits to complete this action.",
|
|
30
|
+
"agent_internal_error": "Something went wrong. Please try again.",
|
|
31
|
+
"step_limit_exceeded": "This Agent tried to process too many steps. Try again with @super for higher step limit.",
|
|
32
|
+
"skill_interrupted": "You were interrupted after executing a skill. Please retry with caution to avoid repeating the skill.",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# In-memory cache for app settings
|
|
36
|
+
_cache: dict[str, dict[str, Any]] = {}
|
|
37
|
+
_cache_ttl = 180 # 3 minutes in seconds
|
|
38
|
+
|
|
39
|
+
|
|
14
40
|
class AppSettingTable(Base):
|
|
15
41
|
"""App settings database table model."""
|
|
16
42
|
|
|
@@ -33,7 +59,7 @@ class AppSettingTable(Base):
|
|
|
33
59
|
DateTime(timezone=True),
|
|
34
60
|
nullable=False,
|
|
35
61
|
server_default=func.now(),
|
|
36
|
-
onupdate=lambda: datetime.now(
|
|
62
|
+
onupdate=lambda: datetime.now(UTC),
|
|
37
63
|
)
|
|
38
64
|
|
|
39
65
|
|
|
@@ -91,7 +117,7 @@ class PaymentSettings(BaseModel):
|
|
|
91
117
|
Field(default=False, description="Whether agent whitelist is enabled"),
|
|
92
118
|
]
|
|
93
119
|
agent_whitelist: Annotated[
|
|
94
|
-
|
|
120
|
+
list[str],
|
|
95
121
|
Field(default_factory=list, description="List of whitelisted agent IDs"),
|
|
96
122
|
]
|
|
97
123
|
|
|
@@ -107,7 +133,7 @@ class PaymentSettings(BaseModel):
|
|
|
107
133
|
"""Round decimal values to 4 decimal places."""
|
|
108
134
|
if isinstance(v, Decimal):
|
|
109
135
|
return v.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
110
|
-
elif isinstance(v,
|
|
136
|
+
elif isinstance(v, int | float):
|
|
111
137
|
return Decimal(str(v)).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
112
138
|
return v
|
|
113
139
|
|
|
@@ -133,31 +159,23 @@ class AppSetting(BaseModel):
|
|
|
133
159
|
|
|
134
160
|
@staticmethod
|
|
135
161
|
async def payment() -> PaymentSettings:
|
|
136
|
-
"""Get payment settings from the database with
|
|
162
|
+
"""Get payment settings from the database with in-memory caching.
|
|
137
163
|
|
|
138
|
-
The settings are cached in
|
|
164
|
+
The settings are cached in memory for 3 minutes.
|
|
139
165
|
|
|
140
166
|
Returns:
|
|
141
167
|
PaymentSettings: Payment settings
|
|
142
168
|
"""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
try:
|
|
154
|
-
payment_data = json.loads(cached_data)
|
|
155
|
-
return PaymentSettings(**payment_data)
|
|
156
|
-
except (json.JSONDecodeError, TypeError):
|
|
157
|
-
# If cache is corrupted, invalidate it
|
|
158
|
-
await redis.delete(cache_key)
|
|
159
|
-
|
|
160
|
-
# If not in cache or cache is invalid, get from database
|
|
169
|
+
cache_key = "payment"
|
|
170
|
+
current_time = time.time()
|
|
171
|
+
|
|
172
|
+
# Check if we have cached data and it's still valid
|
|
173
|
+
if cache_key in _cache:
|
|
174
|
+
cache_entry = _cache[cache_key]
|
|
175
|
+
if current_time - cache_entry["timestamp"] < _cache_ttl:
|
|
176
|
+
return PaymentSettings(**cache_entry["data"])
|
|
177
|
+
|
|
178
|
+
# If not in cache or cache is expired, get from database
|
|
161
179
|
async with get_session() as session:
|
|
162
180
|
# Query the database for the payment settings
|
|
163
181
|
stmt = select(AppSettingTable).where(AppSettingTable.key == "payment")
|
|
@@ -170,11 +188,56 @@ class AppSetting(BaseModel):
|
|
|
170
188
|
# Convert the JSON value to PaymentSettings
|
|
171
189
|
payment_settings = PaymentSettings(**setting.value)
|
|
172
190
|
|
|
173
|
-
# Cache the settings in
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
191
|
+
# Cache the settings in memory
|
|
192
|
+
_cache[cache_key] = {
|
|
193
|
+
"data": payment_settings.model_dump(mode="json"),
|
|
194
|
+
"timestamp": current_time,
|
|
195
|
+
}
|
|
179
196
|
|
|
180
197
|
return payment_settings
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
async def error_message(message_type: SystemMessageType) -> str:
|
|
201
|
+
"""Get error message from the database with in-memory caching, fallback to default.
|
|
202
|
+
|
|
203
|
+
The settings are cached in memory for 3 minutes.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
message_type: The SystemMessageType enum
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
str: Error message from config or default message
|
|
210
|
+
"""
|
|
211
|
+
cache_key = "errors"
|
|
212
|
+
current_time = time.time()
|
|
213
|
+
message_key = message_type.value
|
|
214
|
+
|
|
215
|
+
# Check if we have cached data and it's still valid
|
|
216
|
+
if cache_key in _cache:
|
|
217
|
+
cache_entry = _cache[cache_key]
|
|
218
|
+
if current_time - cache_entry["timestamp"] < _cache_ttl:
|
|
219
|
+
errors_data = cache_entry["data"]
|
|
220
|
+
if errors_data and message_key in errors_data:
|
|
221
|
+
return errors_data[message_key]
|
|
222
|
+
# Return default message if not found in config
|
|
223
|
+
return DEFAULT_SYSTEM_MESSAGES[message_key]
|
|
224
|
+
|
|
225
|
+
# If not in cache or cache is expired, get from database
|
|
226
|
+
async with get_session() as session:
|
|
227
|
+
# Query the database for the errors settings
|
|
228
|
+
stmt = select(AppSettingTable).where(AppSettingTable.key == "errors")
|
|
229
|
+
setting = await session.scalar(stmt)
|
|
230
|
+
|
|
231
|
+
# If settings don't exist, cache None
|
|
232
|
+
errors_data = setting.value if setting else None
|
|
233
|
+
|
|
234
|
+
# Cache the settings in memory
|
|
235
|
+
_cache[cache_key] = {
|
|
236
|
+
"data": errors_data,
|
|
237
|
+
"timestamp": current_time,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# Return configured message if exists, otherwise return default
|
|
241
|
+
if errors_data and message_key in errors_data:
|
|
242
|
+
return errors_data[message_key]
|
|
243
|
+
return DEFAULT_SYSTEM_MESSAGES[message_key]
|
intentkit/models/chat.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import UTC, datetime
|
|
2
4
|
from decimal import Decimal
|
|
3
5
|
from enum import Enum
|
|
4
|
-
from typing import Annotated,
|
|
6
|
+
from typing import Annotated, NotRequired, TypedDict
|
|
5
7
|
|
|
6
8
|
from epyxid import XID
|
|
9
|
+
from intentkit.models.app_setting import AppSetting, SystemMessageType
|
|
7
10
|
from intentkit.models.base import Base
|
|
8
11
|
from intentkit.models.db import get_session
|
|
9
12
|
from pydantic import BaseModel, ConfigDict, Field
|
|
@@ -42,10 +45,12 @@ class AuthorType(str, Enum):
|
|
|
42
45
|
SKILL = "skill"
|
|
43
46
|
TELEGRAM = "telegram"
|
|
44
47
|
TWITTER = "twitter"
|
|
48
|
+
DISCORD = "discord"
|
|
45
49
|
WEB = "web"
|
|
46
50
|
SYSTEM = "system"
|
|
47
51
|
API = "api"
|
|
48
52
|
XMTP = "xmtp"
|
|
53
|
+
X402 = "x402"
|
|
49
54
|
|
|
50
55
|
|
|
51
56
|
class ChatMessageAttachment(TypedDict):
|
|
@@ -63,7 +68,7 @@ class ChatMessageAttachment(TypedDict):
|
|
|
63
68
|
),
|
|
64
69
|
]
|
|
65
70
|
url: Annotated[
|
|
66
|
-
|
|
71
|
+
str | None,
|
|
67
72
|
Field(
|
|
68
73
|
...,
|
|
69
74
|
description="URL of the attachment",
|
|
@@ -71,7 +76,7 @@ class ChatMessageAttachment(TypedDict):
|
|
|
71
76
|
),
|
|
72
77
|
]
|
|
73
78
|
json: Annotated[
|
|
74
|
-
|
|
79
|
+
dict | None,
|
|
75
80
|
Field(
|
|
76
81
|
None,
|
|
77
82
|
description="JSON data of the attachment",
|
|
@@ -112,7 +117,7 @@ class ChatMessageRequest(BaseModel):
|
|
|
112
117
|
),
|
|
113
118
|
]
|
|
114
119
|
app_id: Annotated[
|
|
115
|
-
|
|
120
|
+
str | None,
|
|
116
121
|
Field(
|
|
117
122
|
None,
|
|
118
123
|
description="Optional application identifier",
|
|
@@ -139,21 +144,21 @@ class ChatMessageRequest(BaseModel):
|
|
|
139
144
|
),
|
|
140
145
|
]
|
|
141
146
|
search_mode: Annotated[
|
|
142
|
-
|
|
147
|
+
bool | None,
|
|
143
148
|
Field(
|
|
144
149
|
None,
|
|
145
150
|
description="Optional flag to enable search mode",
|
|
146
151
|
),
|
|
147
152
|
]
|
|
148
153
|
super_mode: Annotated[
|
|
149
|
-
|
|
154
|
+
bool | None,
|
|
150
155
|
Field(
|
|
151
156
|
None,
|
|
152
157
|
description="Optional flag to enable super mode",
|
|
153
158
|
),
|
|
154
159
|
]
|
|
155
160
|
attachments: Annotated[
|
|
156
|
-
|
|
161
|
+
list[ChatMessageAttachment] | None,
|
|
157
162
|
Field(
|
|
158
163
|
None,
|
|
159
164
|
description="Optional list of attachments (links, images, or files)",
|
|
@@ -276,6 +281,10 @@ class ChatMessageTable(Base):
|
|
|
276
281
|
Boolean,
|
|
277
282
|
nullable=True,
|
|
278
283
|
)
|
|
284
|
+
error_type = Column(
|
|
285
|
+
String,
|
|
286
|
+
nullable=True,
|
|
287
|
+
)
|
|
279
288
|
created_at = Column(
|
|
280
289
|
DateTime(timezone=True),
|
|
281
290
|
nullable=False,
|
|
@@ -303,29 +312,29 @@ class ChatMessageCreate(BaseModel):
|
|
|
303
312
|
]
|
|
304
313
|
chat_id: Annotated[str, Field(description="ID of the chat this message belongs to")]
|
|
305
314
|
user_id: Annotated[
|
|
306
|
-
|
|
315
|
+
str | None,
|
|
307
316
|
Field(description="ID of the user this message belongs to or reply to"),
|
|
308
317
|
]
|
|
309
318
|
author_id: Annotated[str, Field(description="ID of the message author")]
|
|
310
319
|
author_type: Annotated[AuthorType, Field(description="Type of the message author")]
|
|
311
320
|
model: Annotated[
|
|
312
|
-
|
|
321
|
+
str | None, Field(None, description="LLM model used if applicable")
|
|
313
322
|
]
|
|
314
323
|
thread_type: Annotated[
|
|
315
|
-
|
|
324
|
+
AuthorType | None,
|
|
316
325
|
Field(None, description="Author Type of the message thread start"),
|
|
317
326
|
]
|
|
318
327
|
reply_to: Annotated[
|
|
319
|
-
|
|
328
|
+
str | None,
|
|
320
329
|
Field(None, description="ID of the message this message is a reply to"),
|
|
321
330
|
]
|
|
322
331
|
message: Annotated[str, Field(description="Content of the message")]
|
|
323
332
|
attachments: Annotated[
|
|
324
|
-
|
|
333
|
+
list[ChatMessageAttachment] | None,
|
|
325
334
|
Field(None, description="List of attachments in the message"),
|
|
326
335
|
]
|
|
327
336
|
skill_calls: Annotated[
|
|
328
|
-
|
|
337
|
+
list[ChatMessageSkillCall] | None,
|
|
329
338
|
Field(None, description="Skill call details"),
|
|
330
339
|
]
|
|
331
340
|
input_tokens: Annotated[
|
|
@@ -338,11 +347,11 @@ class ChatMessageCreate(BaseModel):
|
|
|
338
347
|
float, Field(0.0, description="Time cost for the message in seconds")
|
|
339
348
|
]
|
|
340
349
|
credit_event_id: Annotated[
|
|
341
|
-
|
|
350
|
+
str | None,
|
|
342
351
|
Field(None, description="ID of the credit event for this message"),
|
|
343
352
|
]
|
|
344
353
|
credit_cost: Annotated[
|
|
345
|
-
|
|
354
|
+
Decimal | None,
|
|
346
355
|
Field(None, description="Credit cost for the message in credits"),
|
|
347
356
|
]
|
|
348
357
|
cold_start_cost: Annotated[
|
|
@@ -350,17 +359,21 @@ class ChatMessageCreate(BaseModel):
|
|
|
350
359
|
Field(0.0, description="Cost for the cold start of the message in seconds"),
|
|
351
360
|
]
|
|
352
361
|
app_id: Annotated[
|
|
353
|
-
|
|
362
|
+
str | None,
|
|
354
363
|
Field(None, description="Optional application identifier"),
|
|
355
364
|
]
|
|
356
365
|
search_mode: Annotated[
|
|
357
|
-
|
|
366
|
+
bool | None,
|
|
358
367
|
Field(None, description="Optional flag to enable search mode"),
|
|
359
368
|
]
|
|
360
369
|
super_mode: Annotated[
|
|
361
|
-
|
|
370
|
+
bool | None,
|
|
362
371
|
Field(None, description="Optional flag to enable super mode"),
|
|
363
372
|
]
|
|
373
|
+
error_type: Annotated[
|
|
374
|
+
SystemMessageType | None,
|
|
375
|
+
Field(None, description="Optional error type, used when author_type is system"),
|
|
376
|
+
]
|
|
364
377
|
|
|
365
378
|
async def save_in_session(self, db: AsyncSession) -> "ChatMessage":
|
|
366
379
|
"""Save the chat message to the database.
|
|
@@ -385,6 +398,41 @@ class ChatMessageCreate(BaseModel):
|
|
|
385
398
|
await db.commit()
|
|
386
399
|
return resp
|
|
387
400
|
|
|
401
|
+
@classmethod
|
|
402
|
+
async def from_system_message(
|
|
403
|
+
cls,
|
|
404
|
+
message_type: SystemMessageType,
|
|
405
|
+
agent_id: str,
|
|
406
|
+
chat_id: str,
|
|
407
|
+
user_id: str,
|
|
408
|
+
author_id: str,
|
|
409
|
+
thread_type: AuthorType,
|
|
410
|
+
reply_to: str,
|
|
411
|
+
time_cost: float = 0.0,
|
|
412
|
+
) -> "ChatMessageCreate":
|
|
413
|
+
"""Create a system message.
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
ChatMessageCreate: The created system message
|
|
417
|
+
"""
|
|
418
|
+
|
|
419
|
+
# Get error message (configured or default)
|
|
420
|
+
message = await AppSetting.error_message(message_type)
|
|
421
|
+
|
|
422
|
+
return cls(
|
|
423
|
+
id=str(XID()),
|
|
424
|
+
agent_id=agent_id,
|
|
425
|
+
chat_id=chat_id,
|
|
426
|
+
user_id=user_id,
|
|
427
|
+
author_id=author_id,
|
|
428
|
+
author_type=AuthorType.SYSTEM,
|
|
429
|
+
thread_type=thread_type,
|
|
430
|
+
reply_to=reply_to,
|
|
431
|
+
message=message,
|
|
432
|
+
time_cost=time_cost,
|
|
433
|
+
error_type=message_type,
|
|
434
|
+
)
|
|
435
|
+
|
|
388
436
|
|
|
389
437
|
class ChatMessage(ChatMessageCreate):
|
|
390
438
|
"""Chat message model with all fields including server-generated ones."""
|
|
@@ -459,18 +507,17 @@ class ChatMessage(ChatMessageCreate):
|
|
|
459
507
|
def sanitize_privacy(self) -> "ChatMessage":
|
|
460
508
|
"""Remove sensitive information from the chat message.
|
|
461
509
|
|
|
462
|
-
This method clears the
|
|
510
|
+
This method clears the skill parameters and response
|
|
463
511
|
from skill calls while preserving the structure and metadata.
|
|
464
512
|
|
|
465
513
|
Returns:
|
|
466
514
|
ChatMessage: A new ChatMessage instance with sensitive data removed
|
|
467
515
|
"""
|
|
516
|
+
if self.author_type != AuthorType.SKILL:
|
|
517
|
+
return self
|
|
468
518
|
# Create a copy of the current message
|
|
469
519
|
sanitized_data = self.model_dump()
|
|
470
520
|
|
|
471
|
-
# Clear the message content
|
|
472
|
-
sanitized_data["message"] = ""
|
|
473
|
-
|
|
474
521
|
# Clear sensitive data from skill calls
|
|
475
522
|
if sanitized_data.get("skill_calls"):
|
|
476
523
|
for skill_call in sanitized_data["skill_calls"]:
|
|
@@ -483,7 +530,7 @@ class ChatMessage(ChatMessageCreate):
|
|
|
483
530
|
return ChatMessage.model_validate(sanitized_data)
|
|
484
531
|
|
|
485
532
|
@classmethod
|
|
486
|
-
async def get(cls, message_id: str) ->
|
|
533
|
+
async def get(cls, message_id: str) -> ChatMessage | None:
|
|
487
534
|
async with get_session() as db:
|
|
488
535
|
raw = await db.get(ChatMessageTable, message_id)
|
|
489
536
|
if raw:
|
|
@@ -526,7 +573,7 @@ class ChatTable(Base):
|
|
|
526
573
|
DateTime(timezone=True),
|
|
527
574
|
nullable=False,
|
|
528
575
|
server_default=func.now(),
|
|
529
|
-
onupdate=lambda: datetime.now(
|
|
576
|
+
onupdate=lambda: datetime.now(UTC),
|
|
530
577
|
)
|
|
531
578
|
|
|
532
579
|
|
|
@@ -581,7 +628,7 @@ class Chat(ChatCreate):
|
|
|
581
628
|
]
|
|
582
629
|
|
|
583
630
|
@classmethod
|
|
584
|
-
async def get(cls, id: str) ->
|
|
631
|
+
async def get(cls, id: str) -> "Chat" | None:
|
|
585
632
|
"""Get a chat by its ID.
|
|
586
633
|
|
|
587
634
|
Args:
|
|
@@ -645,7 +692,7 @@ class Chat(ChatCreate):
|
|
|
645
692
|
return self
|
|
646
693
|
|
|
647
694
|
@classmethod
|
|
648
|
-
async def get_by_agent_user(cls, agent_id: str, user_id: str) ->
|
|
695
|
+
async def get_by_agent_user(cls, agent_id: str, user_id: str) -> list["Chat"]:
|
|
649
696
|
"""Get all chats for a specific agent and user.
|
|
650
697
|
|
|
651
698
|
Args:
|
intentkit/models/conversation.py
CHANGED
|
@@ -5,7 +5,7 @@ related to agent generation sessions.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from datetime import datetime
|
|
8
|
-
from typing import Annotated
|
|
8
|
+
from typing import Annotated
|
|
9
9
|
|
|
10
10
|
from epyxid import XID
|
|
11
11
|
from intentkit.models.base import Base
|
|
@@ -103,7 +103,7 @@ class ConversationProjectCreate(BaseModel):
|
|
|
103
103
|
),
|
|
104
104
|
]
|
|
105
105
|
user_id: Annotated[
|
|
106
|
-
|
|
106
|
+
str | None,
|
|
107
107
|
Field(None, description="User ID associated with this project"),
|
|
108
108
|
]
|
|
109
109
|
|
|
@@ -144,7 +144,7 @@ class ConversationProject(ConversationProjectCreate):
|
|
|
144
144
|
]
|
|
145
145
|
|
|
146
146
|
@classmethod
|
|
147
|
-
async def get(cls, project_id: str) ->
|
|
147
|
+
async def get(cls, project_id: str) -> "ConversationProject" | None:
|
|
148
148
|
"""Get a conversation project by ID."""
|
|
149
149
|
async with get_session() as db:
|
|
150
150
|
result = await db.execute(
|
|
@@ -179,8 +179,8 @@ class ConversationProject(ConversationProjectCreate):
|
|
|
179
179
|
|
|
180
180
|
@classmethod
|
|
181
181
|
async def get_by_user(
|
|
182
|
-
cls, user_id:
|
|
183
|
-
) ->
|
|
182
|
+
cls, user_id: str | None = None, limit: int = 50
|
|
183
|
+
) -> list["ConversationProject"]:
|
|
184
184
|
"""Get conversation projects by user ID."""
|
|
185
185
|
async with get_session() as db:
|
|
186
186
|
query = select(ConversationProjectTable).order_by(
|
|
@@ -213,7 +213,7 @@ class ConversationMessageCreate(BaseModel):
|
|
|
213
213
|
role: Annotated[str, Field(description="Role of the message sender")]
|
|
214
214
|
content: Annotated[str, Field(description="Content of the message")]
|
|
215
215
|
message_metadata: Annotated[
|
|
216
|
-
|
|
216
|
+
dict | None,
|
|
217
217
|
Field(None, description="Additional metadata for the message"),
|
|
218
218
|
]
|
|
219
219
|
|
|
@@ -255,8 +255,8 @@ class ConversationMessage(ConversationMessageCreate):
|
|
|
255
255
|
|
|
256
256
|
@classmethod
|
|
257
257
|
async def get_by_project(
|
|
258
|
-
cls, project_id: str, user_id:
|
|
259
|
-
) ->
|
|
258
|
+
cls, project_id: str, user_id: str | None = None
|
|
259
|
+
) -> list["ConversationMessage"]:
|
|
260
260
|
"""Get conversation messages for a project."""
|
|
261
261
|
async with get_session() as db:
|
|
262
262
|
# First check if project exists and user has access
|