intentkit 0.5.0__py3-none-any.whl → 0.5.2__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 +17 -0
- intentkit/abstracts/__init__.py +0 -0
- intentkit/abstracts/agent.py +60 -0
- intentkit/abstracts/api.py +4 -0
- intentkit/abstracts/engine.py +38 -0
- intentkit/abstracts/exception.py +9 -0
- intentkit/abstracts/graph.py +25 -0
- intentkit/abstracts/skill.py +129 -0
- intentkit/abstracts/twitter.py +54 -0
- intentkit/clients/__init__.py +14 -0
- intentkit/clients/cdp.py +53 -0
- intentkit/clients/twitter.py +445 -0
- intentkit/config/__init__.py +0 -0
- intentkit/config/config.py +164 -0
- intentkit/core/__init__.py +0 -0
- intentkit/core/agent.py +191 -0
- intentkit/core/api.py +40 -0
- intentkit/core/client.py +45 -0
- intentkit/core/credit.py +1767 -0
- intentkit/core/engine.py +1018 -0
- intentkit/core/node.py +223 -0
- intentkit/core/prompt.py +58 -0
- intentkit/core/skill.py +124 -0
- intentkit/models/agent.py +1689 -0
- intentkit/models/agent_data.py +810 -0
- intentkit/models/agent_schema.json +733 -0
- intentkit/models/app_setting.py +156 -0
- intentkit/models/base.py +9 -0
- intentkit/models/chat.py +581 -0
- intentkit/models/conversation.py +286 -0
- intentkit/models/credit.py +1406 -0
- intentkit/models/db.py +120 -0
- intentkit/models/db_mig.py +102 -0
- intentkit/models/generator.py +347 -0
- intentkit/models/llm.py +746 -0
- intentkit/models/redis.py +132 -0
- intentkit/models/skill.py +466 -0
- intentkit/models/user.py +243 -0
- intentkit/skills/__init__.py +12 -0
- intentkit/skills/acolyt/__init__.py +83 -0
- intentkit/skills/acolyt/acolyt.jpg +0 -0
- intentkit/skills/acolyt/ask.py +128 -0
- intentkit/skills/acolyt/base.py +28 -0
- intentkit/skills/acolyt/schema.json +89 -0
- intentkit/skills/aixbt/README.md +71 -0
- intentkit/skills/aixbt/__init__.py +73 -0
- intentkit/skills/aixbt/aixbt.jpg +0 -0
- intentkit/skills/aixbt/base.py +21 -0
- intentkit/skills/aixbt/projects.py +153 -0
- intentkit/skills/aixbt/schema.json +99 -0
- intentkit/skills/allora/__init__.py +83 -0
- intentkit/skills/allora/allora.jpeg +0 -0
- intentkit/skills/allora/base.py +28 -0
- intentkit/skills/allora/price.py +130 -0
- intentkit/skills/allora/schema.json +89 -0
- intentkit/skills/base.py +174 -0
- intentkit/skills/carv/README.md +95 -0
- intentkit/skills/carv/__init__.py +121 -0
- intentkit/skills/carv/base.py +183 -0
- intentkit/skills/carv/carv.webp +0 -0
- intentkit/skills/carv/fetch_news.py +92 -0
- intentkit/skills/carv/onchain_query.py +164 -0
- intentkit/skills/carv/schema.json +137 -0
- intentkit/skills/carv/token_info_and_price.py +110 -0
- intentkit/skills/cdp/__init__.py +137 -0
- intentkit/skills/cdp/base.py +21 -0
- intentkit/skills/cdp/cdp.png +0 -0
- intentkit/skills/cdp/get_balance.py +81 -0
- intentkit/skills/cdp/schema.json +473 -0
- intentkit/skills/chainlist/README.md +38 -0
- intentkit/skills/chainlist/__init__.py +54 -0
- intentkit/skills/chainlist/base.py +21 -0
- intentkit/skills/chainlist/chain_lookup.py +208 -0
- intentkit/skills/chainlist/chainlist.png +0 -0
- intentkit/skills/chainlist/schema.json +47 -0
- intentkit/skills/common/__init__.py +82 -0
- intentkit/skills/common/base.py +21 -0
- intentkit/skills/common/common.jpg +0 -0
- intentkit/skills/common/current_time.py +84 -0
- intentkit/skills/common/schema.json +57 -0
- intentkit/skills/cookiefun/README.md +121 -0
- intentkit/skills/cookiefun/__init__.py +78 -0
- intentkit/skills/cookiefun/base.py +41 -0
- intentkit/skills/cookiefun/constants.py +18 -0
- intentkit/skills/cookiefun/cookiefun.png +0 -0
- intentkit/skills/cookiefun/get_account_details.py +171 -0
- intentkit/skills/cookiefun/get_account_feed.py +282 -0
- intentkit/skills/cookiefun/get_account_smart_followers.py +181 -0
- intentkit/skills/cookiefun/get_sectors.py +128 -0
- intentkit/skills/cookiefun/schema.json +155 -0
- intentkit/skills/cookiefun/search_accounts.py +225 -0
- intentkit/skills/cryptocompare/__init__.py +130 -0
- intentkit/skills/cryptocompare/api.py +159 -0
- intentkit/skills/cryptocompare/base.py +303 -0
- intentkit/skills/cryptocompare/cryptocompare.png +0 -0
- intentkit/skills/cryptocompare/fetch_news.py +96 -0
- intentkit/skills/cryptocompare/fetch_price.py +99 -0
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +113 -0
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +109 -0
- intentkit/skills/cryptocompare/fetch_top_volume.py +108 -0
- intentkit/skills/cryptocompare/fetch_trading_signals.py +107 -0
- intentkit/skills/cryptocompare/schema.json +168 -0
- intentkit/skills/cryptopanic/__init__.py +108 -0
- intentkit/skills/cryptopanic/base.py +51 -0
- intentkit/skills/cryptopanic/cryptopanic.png +0 -0
- intentkit/skills/cryptopanic/fetch_crypto_news.py +153 -0
- intentkit/skills/cryptopanic/fetch_crypto_sentiment.py +136 -0
- intentkit/skills/cryptopanic/schema.json +103 -0
- intentkit/skills/dapplooker/README.md +92 -0
- intentkit/skills/dapplooker/__init__.py +83 -0
- intentkit/skills/dapplooker/base.py +26 -0
- intentkit/skills/dapplooker/dapplooker.jpg +0 -0
- intentkit/skills/dapplooker/dapplooker_token_data.py +476 -0
- intentkit/skills/dapplooker/schema.json +91 -0
- intentkit/skills/defillama/__init__.py +323 -0
- intentkit/skills/defillama/api.py +315 -0
- intentkit/skills/defillama/base.py +135 -0
- intentkit/skills/defillama/coins/__init__.py +0 -0
- intentkit/skills/defillama/coins/fetch_batch_historical_prices.py +116 -0
- intentkit/skills/defillama/coins/fetch_block.py +98 -0
- intentkit/skills/defillama/coins/fetch_current_prices.py +105 -0
- intentkit/skills/defillama/coins/fetch_first_price.py +100 -0
- intentkit/skills/defillama/coins/fetch_historical_prices.py +110 -0
- intentkit/skills/defillama/coins/fetch_price_chart.py +109 -0
- intentkit/skills/defillama/coins/fetch_price_percentage.py +93 -0
- intentkit/skills/defillama/config/__init__.py +0 -0
- intentkit/skills/defillama/config/chains.py +433 -0
- intentkit/skills/defillama/defillama.jpeg +0 -0
- intentkit/skills/defillama/fees/__init__.py +0 -0
- intentkit/skills/defillama/fees/fetch_fees_overview.py +130 -0
- intentkit/skills/defillama/schema.json +383 -0
- intentkit/skills/defillama/stablecoins/__init__.py +0 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_chains.py +100 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_charts.py +129 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoin_prices.py +83 -0
- intentkit/skills/defillama/stablecoins/fetch_stablecoins.py +126 -0
- intentkit/skills/defillama/tests/__init__.py +0 -0
- intentkit/skills/defillama/tests/api_integration.test.py +192 -0
- intentkit/skills/defillama/tests/api_unit.test.py +583 -0
- intentkit/skills/defillama/tvl/__init__.py +0 -0
- intentkit/skills/defillama/tvl/fetch_chain_historical_tvl.py +106 -0
- intentkit/skills/defillama/tvl/fetch_chains.py +107 -0
- intentkit/skills/defillama/tvl/fetch_historical_tvl.py +91 -0
- intentkit/skills/defillama/tvl/fetch_protocol.py +207 -0
- intentkit/skills/defillama/tvl/fetch_protocol_current_tvl.py +93 -0
- intentkit/skills/defillama/tvl/fetch_protocols.py +196 -0
- intentkit/skills/defillama/volumes/__init__.py +0 -0
- intentkit/skills/defillama/volumes/fetch_dex_overview.py +157 -0
- intentkit/skills/defillama/volumes/fetch_dex_summary.py +123 -0
- intentkit/skills/defillama/volumes/fetch_options_overview.py +131 -0
- intentkit/skills/defillama/yields/__init__.py +0 -0
- intentkit/skills/defillama/yields/fetch_pool_chart.py +100 -0
- intentkit/skills/defillama/yields/fetch_pools.py +126 -0
- intentkit/skills/dexscreener/__init__.py +93 -0
- intentkit/skills/dexscreener/base.py +133 -0
- intentkit/skills/dexscreener/dexscreener.png +0 -0
- intentkit/skills/dexscreener/model/__init__.py +0 -0
- intentkit/skills/dexscreener/model/search_token_response.py +82 -0
- intentkit/skills/dexscreener/schema.json +48 -0
- intentkit/skills/dexscreener/search_token.py +321 -0
- intentkit/skills/dune_analytics/__init__.py +103 -0
- intentkit/skills/dune_analytics/base.py +46 -0
- intentkit/skills/dune_analytics/dune.png +0 -0
- intentkit/skills/dune_analytics/fetch_kol_buys.py +128 -0
- intentkit/skills/dune_analytics/fetch_nation_metrics.py +237 -0
- intentkit/skills/dune_analytics/schema.json +99 -0
- intentkit/skills/elfa/README.md +100 -0
- intentkit/skills/elfa/__init__.py +123 -0
- intentkit/skills/elfa/base.py +28 -0
- intentkit/skills/elfa/elfa.jpg +0 -0
- intentkit/skills/elfa/mention.py +504 -0
- intentkit/skills/elfa/schema.json +153 -0
- intentkit/skills/elfa/stats.py +118 -0
- intentkit/skills/elfa/tokens.py +126 -0
- intentkit/skills/enso/README.md +75 -0
- intentkit/skills/enso/__init__.py +114 -0
- intentkit/skills/enso/abi/__init__.py +0 -0
- intentkit/skills/enso/abi/approval.py +279 -0
- intentkit/skills/enso/abi/erc20.py +14 -0
- intentkit/skills/enso/abi/route.py +129 -0
- intentkit/skills/enso/base.py +44 -0
- intentkit/skills/enso/best_yield.py +286 -0
- intentkit/skills/enso/enso.jpg +0 -0
- intentkit/skills/enso/networks.py +105 -0
- intentkit/skills/enso/prices.py +93 -0
- intentkit/skills/enso/route.py +300 -0
- intentkit/skills/enso/schema.json +212 -0
- intentkit/skills/enso/tokens.py +223 -0
- intentkit/skills/enso/wallet.py +381 -0
- intentkit/skills/github/README.md +63 -0
- intentkit/skills/github/__init__.py +54 -0
- intentkit/skills/github/base.py +21 -0
- intentkit/skills/github/github.jpg +0 -0
- intentkit/skills/github/github_search.py +183 -0
- intentkit/skills/github/schema.json +59 -0
- intentkit/skills/heurist/__init__.py +143 -0
- intentkit/skills/heurist/base.py +26 -0
- intentkit/skills/heurist/heurist.png +0 -0
- intentkit/skills/heurist/image_generation_animagine_xl.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_comics.py +162 -0
- intentkit/skills/heurist/image_generation_arthemy_real.py +162 -0
- intentkit/skills/heurist/image_generation_braindance.py +162 -0
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +162 -0
- intentkit/skills/heurist/image_generation_flux_1_dev.py +162 -0
- intentkit/skills/heurist/image_generation_sdxl.py +161 -0
- intentkit/skills/heurist/schema.json +196 -0
- intentkit/skills/lifi/README.md +294 -0
- intentkit/skills/lifi/__init__.py +141 -0
- intentkit/skills/lifi/base.py +21 -0
- intentkit/skills/lifi/lifi.png +0 -0
- intentkit/skills/lifi/schema.json +89 -0
- intentkit/skills/lifi/token_execute.py +472 -0
- intentkit/skills/lifi/token_quote.py +190 -0
- intentkit/skills/lifi/utils.py +656 -0
- intentkit/skills/moralis/README.md +490 -0
- intentkit/skills/moralis/__init__.py +110 -0
- intentkit/skills/moralis/api.py +281 -0
- intentkit/skills/moralis/base.py +55 -0
- intentkit/skills/moralis/fetch_chain_portfolio.py +191 -0
- intentkit/skills/moralis/fetch_nft_portfolio.py +284 -0
- intentkit/skills/moralis/fetch_solana_portfolio.py +331 -0
- intentkit/skills/moralis/fetch_wallet_portfolio.py +301 -0
- intentkit/skills/moralis/moralis.png +0 -0
- intentkit/skills/moralis/schema.json +156 -0
- intentkit/skills/moralis/tests/__init__.py +0 -0
- intentkit/skills/moralis/tests/test_wallet.py +511 -0
- intentkit/skills/nation/__init__.py +62 -0
- intentkit/skills/nation/base.py +31 -0
- intentkit/skills/nation/nation.png +0 -0
- intentkit/skills/nation/nft_check.py +106 -0
- intentkit/skills/nation/schema.json +58 -0
- intentkit/skills/openai/__init__.py +107 -0
- intentkit/skills/openai/base.py +32 -0
- intentkit/skills/openai/dalle_image_generation.py +128 -0
- intentkit/skills/openai/gpt_image_generation.py +152 -0
- intentkit/skills/openai/gpt_image_to_image.py +186 -0
- intentkit/skills/openai/image_to_text.py +126 -0
- intentkit/skills/openai/openai.png +0 -0
- intentkit/skills/openai/schema.json +139 -0
- intentkit/skills/portfolio/README.md +55 -0
- intentkit/skills/portfolio/__init__.py +151 -0
- intentkit/skills/portfolio/base.py +107 -0
- intentkit/skills/portfolio/constants.py +9 -0
- intentkit/skills/portfolio/moralis.png +0 -0
- intentkit/skills/portfolio/schema.json +237 -0
- intentkit/skills/portfolio/token_balances.py +155 -0
- intentkit/skills/portfolio/wallet_approvals.py +102 -0
- intentkit/skills/portfolio/wallet_defi_positions.py +80 -0
- intentkit/skills/portfolio/wallet_history.py +155 -0
- intentkit/skills/portfolio/wallet_net_worth.py +112 -0
- intentkit/skills/portfolio/wallet_nfts.py +139 -0
- intentkit/skills/portfolio/wallet_profitability.py +101 -0
- intentkit/skills/portfolio/wallet_profitability_summary.py +91 -0
- intentkit/skills/portfolio/wallet_stats.py +79 -0
- intentkit/skills/portfolio/wallet_swaps.py +147 -0
- intentkit/skills/skills.toml +103 -0
- intentkit/skills/slack/__init__.py +98 -0
- intentkit/skills/slack/base.py +55 -0
- intentkit/skills/slack/get_channel.py +109 -0
- intentkit/skills/slack/get_message.py +136 -0
- intentkit/skills/slack/schedule_message.py +92 -0
- intentkit/skills/slack/schema.json +135 -0
- intentkit/skills/slack/send_message.py +81 -0
- intentkit/skills/slack/slack.jpg +0 -0
- intentkit/skills/system/__init__.py +90 -0
- intentkit/skills/system/base.py +22 -0
- intentkit/skills/system/read_agent_api_key.py +87 -0
- intentkit/skills/system/regenerate_agent_api_key.py +77 -0
- intentkit/skills/system/schema.json +53 -0
- intentkit/skills/system/system.svg +76 -0
- intentkit/skills/tavily/README.md +86 -0
- intentkit/skills/tavily/__init__.py +91 -0
- intentkit/skills/tavily/base.py +27 -0
- intentkit/skills/tavily/schema.json +119 -0
- intentkit/skills/tavily/tavily.jpg +0 -0
- intentkit/skills/tavily/tavily_extract.py +147 -0
- intentkit/skills/tavily/tavily_search.py +139 -0
- intentkit/skills/token/README.md +89 -0
- intentkit/skills/token/__init__.py +107 -0
- intentkit/skills/token/base.py +154 -0
- intentkit/skills/token/constants.py +9 -0
- intentkit/skills/token/erc20_transfers.py +145 -0
- intentkit/skills/token/moralis.png +0 -0
- intentkit/skills/token/schema.json +141 -0
- intentkit/skills/token/token_analytics.py +81 -0
- intentkit/skills/token/token_price.py +132 -0
- intentkit/skills/token/token_search.py +121 -0
- intentkit/skills/twitter/__init__.py +146 -0
- intentkit/skills/twitter/base.py +68 -0
- intentkit/skills/twitter/follow_user.py +69 -0
- intentkit/skills/twitter/get_mentions.py +124 -0
- intentkit/skills/twitter/get_timeline.py +111 -0
- intentkit/skills/twitter/get_user_by_username.py +84 -0
- intentkit/skills/twitter/get_user_tweets.py +123 -0
- intentkit/skills/twitter/like_tweet.py +65 -0
- intentkit/skills/twitter/post_tweet.py +90 -0
- intentkit/skills/twitter/reply_tweet.py +98 -0
- intentkit/skills/twitter/retweet.py +76 -0
- intentkit/skills/twitter/schema.json +258 -0
- intentkit/skills/twitter/search_tweets.py +115 -0
- intentkit/skills/twitter/twitter.png +0 -0
- intentkit/skills/unrealspeech/__init__.py +55 -0
- intentkit/skills/unrealspeech/base.py +21 -0
- intentkit/skills/unrealspeech/schema.json +100 -0
- intentkit/skills/unrealspeech/text_to_speech.py +177 -0
- intentkit/skills/unrealspeech/unrealspeech.jpg +0 -0
- intentkit/skills/venice_audio/__init__.py +106 -0
- intentkit/skills/venice_audio/base.py +119 -0
- intentkit/skills/venice_audio/input.py +41 -0
- intentkit/skills/venice_audio/schema.json +152 -0
- intentkit/skills/venice_audio/venice_audio.py +240 -0
- intentkit/skills/venice_audio/venice_logo.jpg +0 -0
- intentkit/skills/venice_image/README.md +119 -0
- intentkit/skills/venice_image/__init__.py +154 -0
- intentkit/skills/venice_image/api.py +138 -0
- intentkit/skills/venice_image/base.py +188 -0
- intentkit/skills/venice_image/config.py +35 -0
- intentkit/skills/venice_image/image_enhance/README.md +119 -0
- intentkit/skills/venice_image/image_enhance/__init__.py +0 -0
- intentkit/skills/venice_image/image_enhance/image_enhance.py +80 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_base.py +23 -0
- intentkit/skills/venice_image/image_enhance/image_enhance_input.py +40 -0
- intentkit/skills/venice_image/image_generation/README.md +144 -0
- intentkit/skills/venice_image/image_generation/__init__.py +0 -0
- intentkit/skills/venice_image/image_generation/image_generation_base.py +117 -0
- intentkit/skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev.py +27 -0
- intentkit/skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_input.py +158 -0
- intentkit/skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_pony_realism.py +26 -0
- intentkit/skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -0
- intentkit/skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -0
- intentkit/skills/venice_image/image_upscale/README.md +111 -0
- intentkit/skills/venice_image/image_upscale/__init__.py +0 -0
- intentkit/skills/venice_image/image_upscale/image_upscale.py +90 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_base.py +23 -0
- intentkit/skills/venice_image/image_upscale/image_upscale_input.py +22 -0
- intentkit/skills/venice_image/image_vision/README.md +112 -0
- intentkit/skills/venice_image/image_vision/__init__.py +0 -0
- intentkit/skills/venice_image/image_vision/image_vision.py +100 -0
- intentkit/skills/venice_image/image_vision/image_vision_base.py +17 -0
- intentkit/skills/venice_image/image_vision/image_vision_input.py +9 -0
- intentkit/skills/venice_image/schema.json +267 -0
- intentkit/skills/venice_image/utils.py +78 -0
- intentkit/skills/venice_image/venice_image.jpg +0 -0
- intentkit/skills/web_scraper/README.md +82 -0
- intentkit/skills/web_scraper/__init__.py +92 -0
- intentkit/skills/web_scraper/base.py +21 -0
- intentkit/skills/web_scraper/langchain.png +0 -0
- intentkit/skills/web_scraper/schema.json +115 -0
- intentkit/skills/web_scraper/scrape_and_index.py +327 -0
- intentkit/utils/__init__.py +1 -0
- intentkit/utils/chain.py +436 -0
- intentkit/utils/error.py +134 -0
- intentkit/utils/logging.py +70 -0
- intentkit/utils/middleware.py +61 -0
- intentkit/utils/random.py +16 -0
- intentkit/utils/s3.py +267 -0
- intentkit/utils/slack_alert.py +79 -0
- intentkit/utils/tx.py +37 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/METADATA +1 -1
- intentkit-0.5.2.dist-info/RECORD +365 -0
- intentkit-0.5.0.dist-info/RECORD +0 -4
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/WHEEL +0 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.2.dist-info}/licenses/LICENSE +0 -0
intentkit/models/chat.py
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Annotated, List, NotRequired, Optional, TypedDict
|
|
5
|
+
|
|
6
|
+
from epyxid import XID
|
|
7
|
+
from intentkit.models.base import Base
|
|
8
|
+
from intentkit.models.db import get_session
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
10
|
+
from sqlalchemy import (
|
|
11
|
+
Column,
|
|
12
|
+
DateTime,
|
|
13
|
+
Float,
|
|
14
|
+
Index,
|
|
15
|
+
Integer,
|
|
16
|
+
Numeric,
|
|
17
|
+
String,
|
|
18
|
+
desc,
|
|
19
|
+
func,
|
|
20
|
+
select,
|
|
21
|
+
update,
|
|
22
|
+
)
|
|
23
|
+
from sqlalchemy.dialects.postgresql import JSON, JSONB
|
|
24
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ChatMessageAttachmentType(str, Enum):
|
|
28
|
+
"""Type of chat message attachment."""
|
|
29
|
+
|
|
30
|
+
LINK = "link"
|
|
31
|
+
IMAGE = "image"
|
|
32
|
+
FILE = "file"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AuthorType(str, Enum):
|
|
36
|
+
"""Type of message author."""
|
|
37
|
+
|
|
38
|
+
AGENT = "agent"
|
|
39
|
+
TRIGGER = "trigger"
|
|
40
|
+
SKILL = "skill"
|
|
41
|
+
TELEGRAM = "telegram"
|
|
42
|
+
TWITTER = "twitter"
|
|
43
|
+
WEB = "web"
|
|
44
|
+
SYSTEM = "system"
|
|
45
|
+
API = "api"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ChatMessageAttachment(TypedDict):
|
|
49
|
+
"""Chat message attachment model.
|
|
50
|
+
|
|
51
|
+
An attachment can be a link, image, or file that is associated with a chat message.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
type: Annotated[
|
|
55
|
+
ChatMessageAttachmentType,
|
|
56
|
+
Field(
|
|
57
|
+
...,
|
|
58
|
+
description="Type of the attachment (link, image, or file)",
|
|
59
|
+
examples=["link"],
|
|
60
|
+
),
|
|
61
|
+
]
|
|
62
|
+
url: Annotated[
|
|
63
|
+
str,
|
|
64
|
+
Field(
|
|
65
|
+
...,
|
|
66
|
+
description="URL of the attachment",
|
|
67
|
+
examples=["https://example.com/image.jpg"],
|
|
68
|
+
),
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ChatMessageSkillCall(TypedDict):
|
|
73
|
+
"""TypedDict for skill call details."""
|
|
74
|
+
|
|
75
|
+
id: NotRequired[str]
|
|
76
|
+
name: str
|
|
77
|
+
parameters: dict
|
|
78
|
+
success: bool
|
|
79
|
+
response: NotRequired[
|
|
80
|
+
str
|
|
81
|
+
] # Optional response from the skill call, trimmed to 100 characters
|
|
82
|
+
error_message: NotRequired[str] # Optional error message from the skill call
|
|
83
|
+
credit_event_id: NotRequired[str] # ID of the credit event for this skill call
|
|
84
|
+
credit_cost: NotRequired[Decimal] # Credit cost for the skill call
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ChatMessageRequest(BaseModel):
|
|
88
|
+
"""Request model for chat messages.
|
|
89
|
+
|
|
90
|
+
This model represents the request body for creating a new chat message.
|
|
91
|
+
It contains the necessary fields to identify the chat context, user,
|
|
92
|
+
and message content, along with optional attachments.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
chat_id: Annotated[
|
|
96
|
+
str,
|
|
97
|
+
Field(
|
|
98
|
+
...,
|
|
99
|
+
description="Unique identifier for the chat thread",
|
|
100
|
+
examples=["chat-123"],
|
|
101
|
+
min_length=1,
|
|
102
|
+
),
|
|
103
|
+
]
|
|
104
|
+
user_id: Annotated[
|
|
105
|
+
str,
|
|
106
|
+
Field(
|
|
107
|
+
...,
|
|
108
|
+
description="Unique identifier of the user sending the message",
|
|
109
|
+
examples=["user-456"],
|
|
110
|
+
min_length=1,
|
|
111
|
+
),
|
|
112
|
+
]
|
|
113
|
+
message: Annotated[
|
|
114
|
+
str,
|
|
115
|
+
Field(
|
|
116
|
+
...,
|
|
117
|
+
description="Content of the message",
|
|
118
|
+
examples=["Hello, how can you help me today?"],
|
|
119
|
+
min_length=1,
|
|
120
|
+
max_length=65535,
|
|
121
|
+
),
|
|
122
|
+
]
|
|
123
|
+
attachments: Annotated[
|
|
124
|
+
Optional[List[ChatMessageAttachment]],
|
|
125
|
+
Field(
|
|
126
|
+
None,
|
|
127
|
+
description="Optional list of attachments (links, images, or files)",
|
|
128
|
+
examples=[[{"type": "link", "url": "https://example.com"}]],
|
|
129
|
+
),
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
model_config = ConfigDict(
|
|
133
|
+
use_enum_values=True,
|
|
134
|
+
json_schema_extra={
|
|
135
|
+
"example": {
|
|
136
|
+
"chat_id": "chat-123",
|
|
137
|
+
"user_id": "user-456",
|
|
138
|
+
"message": "Hello, how can you help me today?",
|
|
139
|
+
"attachments": [
|
|
140
|
+
{
|
|
141
|
+
"type": "link",
|
|
142
|
+
"url": "https://example.com",
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class ChatMessageTable(Base):
|
|
151
|
+
"""Chat message database table model."""
|
|
152
|
+
|
|
153
|
+
__tablename__ = "chat_messages"
|
|
154
|
+
__table_args__ = (
|
|
155
|
+
Index("ix_chat_messages_chat_id", "chat_id"),
|
|
156
|
+
Index("ix_chat_messages_agent_id_author_type", "agent_id", "author_type"),
|
|
157
|
+
Index("ix_chat_messages_agent_id_chat_id", "agent_id", "chat_id"),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
id = Column(
|
|
161
|
+
String,
|
|
162
|
+
primary_key=True,
|
|
163
|
+
)
|
|
164
|
+
agent_id = Column(
|
|
165
|
+
String,
|
|
166
|
+
nullable=False,
|
|
167
|
+
)
|
|
168
|
+
chat_id = Column(
|
|
169
|
+
String,
|
|
170
|
+
nullable=False,
|
|
171
|
+
)
|
|
172
|
+
user_id = Column(
|
|
173
|
+
String,
|
|
174
|
+
nullable=True,
|
|
175
|
+
)
|
|
176
|
+
author_id = Column(
|
|
177
|
+
String,
|
|
178
|
+
nullable=False,
|
|
179
|
+
)
|
|
180
|
+
author_type = Column(
|
|
181
|
+
String,
|
|
182
|
+
nullable=False,
|
|
183
|
+
)
|
|
184
|
+
model = Column(
|
|
185
|
+
String,
|
|
186
|
+
nullable=True,
|
|
187
|
+
)
|
|
188
|
+
thread_type = Column(
|
|
189
|
+
String,
|
|
190
|
+
nullable=True,
|
|
191
|
+
)
|
|
192
|
+
reply_to = Column(
|
|
193
|
+
String,
|
|
194
|
+
nullable=True,
|
|
195
|
+
)
|
|
196
|
+
message = Column(
|
|
197
|
+
String,
|
|
198
|
+
nullable=False,
|
|
199
|
+
)
|
|
200
|
+
attachments = Column(
|
|
201
|
+
JSON().with_variant(JSONB(), "postgresql"),
|
|
202
|
+
nullable=True,
|
|
203
|
+
)
|
|
204
|
+
skill_calls = Column(
|
|
205
|
+
JSON().with_variant(JSONB(), "postgresql"),
|
|
206
|
+
nullable=True,
|
|
207
|
+
)
|
|
208
|
+
input_tokens = Column(
|
|
209
|
+
Integer,
|
|
210
|
+
default=0,
|
|
211
|
+
)
|
|
212
|
+
output_tokens = Column(
|
|
213
|
+
Integer,
|
|
214
|
+
default=0,
|
|
215
|
+
)
|
|
216
|
+
time_cost = Column(
|
|
217
|
+
Float,
|
|
218
|
+
default=0,
|
|
219
|
+
)
|
|
220
|
+
credit_event_id = Column(
|
|
221
|
+
String,
|
|
222
|
+
nullable=True,
|
|
223
|
+
)
|
|
224
|
+
credit_cost = Column(
|
|
225
|
+
Numeric(22, 4),
|
|
226
|
+
nullable=True,
|
|
227
|
+
)
|
|
228
|
+
cold_start_cost = Column(
|
|
229
|
+
Float,
|
|
230
|
+
default=0,
|
|
231
|
+
)
|
|
232
|
+
created_at = Column(
|
|
233
|
+
DateTime(timezone=True),
|
|
234
|
+
nullable=False,
|
|
235
|
+
server_default=func.now(),
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class ChatMessageCreate(BaseModel):
|
|
240
|
+
"""Base model for creating chat messages with fields needed for creation."""
|
|
241
|
+
|
|
242
|
+
model_config = ConfigDict(
|
|
243
|
+
use_enum_values=True,
|
|
244
|
+
from_attributes=True,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
id: Annotated[
|
|
248
|
+
str,
|
|
249
|
+
Field(
|
|
250
|
+
default_factory=lambda: str(XID()),
|
|
251
|
+
description="Unique identifier for the chat message",
|
|
252
|
+
),
|
|
253
|
+
]
|
|
254
|
+
agent_id: Annotated[
|
|
255
|
+
str, Field(description="ID of the agent this message belongs to")
|
|
256
|
+
]
|
|
257
|
+
chat_id: Annotated[str, Field(description="ID of the chat this message belongs to")]
|
|
258
|
+
user_id: Annotated[
|
|
259
|
+
Optional[str],
|
|
260
|
+
Field(description="ID of the user this message belongs to or reply to"),
|
|
261
|
+
]
|
|
262
|
+
author_id: Annotated[str, Field(description="ID of the message author")]
|
|
263
|
+
author_type: Annotated[AuthorType, Field(description="Type of the message author")]
|
|
264
|
+
model: Annotated[
|
|
265
|
+
Optional[str], Field(None, description="LLM model used if applicable")
|
|
266
|
+
]
|
|
267
|
+
thread_type: Annotated[
|
|
268
|
+
Optional[AuthorType],
|
|
269
|
+
Field(None, description="Author Type of the message thread start"),
|
|
270
|
+
]
|
|
271
|
+
reply_to: Annotated[
|
|
272
|
+
Optional[str],
|
|
273
|
+
Field(None, description="ID of the message this message is a reply to"),
|
|
274
|
+
]
|
|
275
|
+
message: Annotated[str, Field(description="Content of the message")]
|
|
276
|
+
attachments: Annotated[
|
|
277
|
+
Optional[List[ChatMessageAttachment]],
|
|
278
|
+
Field(None, description="List of attachments in the message"),
|
|
279
|
+
]
|
|
280
|
+
skill_calls: Annotated[
|
|
281
|
+
Optional[List[ChatMessageSkillCall]],
|
|
282
|
+
Field(None, description="Skill call details"),
|
|
283
|
+
]
|
|
284
|
+
input_tokens: Annotated[
|
|
285
|
+
int, Field(0, description="Number of tokens in the input message")
|
|
286
|
+
]
|
|
287
|
+
output_tokens: Annotated[
|
|
288
|
+
int, Field(0, description="Number of tokens in the output message")
|
|
289
|
+
]
|
|
290
|
+
time_cost: Annotated[
|
|
291
|
+
float, Field(0.0, description="Time cost for the message in seconds")
|
|
292
|
+
]
|
|
293
|
+
credit_event_id: Annotated[
|
|
294
|
+
Optional[str],
|
|
295
|
+
Field(None, description="ID of the credit event for this message"),
|
|
296
|
+
]
|
|
297
|
+
credit_cost: Annotated[
|
|
298
|
+
Optional[Decimal],
|
|
299
|
+
Field(None, description="Credit cost for the message in credits"),
|
|
300
|
+
]
|
|
301
|
+
cold_start_cost: Annotated[
|
|
302
|
+
float,
|
|
303
|
+
Field(0.0, description="Cost for the cold start of the message in seconds"),
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
async def save_in_session(self, db: AsyncSession) -> "ChatMessage":
|
|
307
|
+
"""Save the chat message to the database.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
ChatMessage: The saved chat message with all fields populated
|
|
311
|
+
"""
|
|
312
|
+
message_record = ChatMessageTable(**self.model_dump(mode="json"))
|
|
313
|
+
db.add(message_record)
|
|
314
|
+
await db.flush()
|
|
315
|
+
await db.refresh(message_record)
|
|
316
|
+
return ChatMessage.model_validate(message_record)
|
|
317
|
+
|
|
318
|
+
async def save(self) -> "ChatMessage":
|
|
319
|
+
"""Save the chat message to the database.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
ChatMessage: The saved chat message with all fields populated
|
|
323
|
+
"""
|
|
324
|
+
async with get_session() as db:
|
|
325
|
+
resp = await self.save_in_session(db)
|
|
326
|
+
await db.commit()
|
|
327
|
+
return resp
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class ChatMessage(ChatMessageCreate):
|
|
331
|
+
"""Chat message model with all fields including server-generated ones."""
|
|
332
|
+
|
|
333
|
+
model_config = ConfigDict(
|
|
334
|
+
use_enum_values=True,
|
|
335
|
+
json_encoders={
|
|
336
|
+
datetime: lambda v: v.isoformat(timespec="milliseconds"),
|
|
337
|
+
},
|
|
338
|
+
from_attributes=True,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
created_at: Annotated[
|
|
342
|
+
datetime, Field(description="Timestamp when this message was created")
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
def __str__(self):
|
|
346
|
+
resp = ""
|
|
347
|
+
if self.skill_calls:
|
|
348
|
+
for call in self.skill_calls:
|
|
349
|
+
resp += f"{call['name']} {call['parameters']}: {call['response'] if call['success'] else call['error_message']}\n"
|
|
350
|
+
resp += "\n"
|
|
351
|
+
resp += self.message
|
|
352
|
+
return resp
|
|
353
|
+
|
|
354
|
+
def debug_format(self) -> str:
|
|
355
|
+
"""Format this ChatMessage for debug output.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
str: Formatted debug string for the message
|
|
359
|
+
"""
|
|
360
|
+
resp = ""
|
|
361
|
+
|
|
362
|
+
if self.cold_start_cost:
|
|
363
|
+
resp += "[ Agent cold start ... ]\n"
|
|
364
|
+
resp += f"\n------------------- start cost: {self.cold_start_cost:.3f} seconds\n\n"
|
|
365
|
+
|
|
366
|
+
if self.author_type == AuthorType.SKILL:
|
|
367
|
+
resp += f"[ Skill Calls: ] ({self.created_at.strftime('%Y-%m-%d %H:%M:%S')} UTC)\n\n"
|
|
368
|
+
for skill_call in self.skill_calls:
|
|
369
|
+
resp += f" {skill_call['name']}: {skill_call['parameters']}\n"
|
|
370
|
+
if skill_call["success"]:
|
|
371
|
+
resp += f" Success: {skill_call.get('response', '')}\n"
|
|
372
|
+
else:
|
|
373
|
+
resp += f" Failed: {skill_call.get('error_message', '')}\n"
|
|
374
|
+
resp += (
|
|
375
|
+
f"\n------------------- skill cost: {self.time_cost:.3f} seconds\n\n"
|
|
376
|
+
)
|
|
377
|
+
elif self.author_type == AuthorType.AGENT:
|
|
378
|
+
resp += (
|
|
379
|
+
f"[ Agent: ] ({self.created_at.strftime('%Y-%m-%d %H:%M:%S')} UTC)\n\n"
|
|
380
|
+
)
|
|
381
|
+
resp += f" {self.message}\n"
|
|
382
|
+
resp += (
|
|
383
|
+
f"\n------------------- agent cost: {self.time_cost:.3f} seconds\n\n"
|
|
384
|
+
)
|
|
385
|
+
elif self.author_type == AuthorType.SYSTEM:
|
|
386
|
+
resp += (
|
|
387
|
+
f"[ System: ] ({self.created_at.strftime('%Y-%m-%d %H:%M:%S')} UTC)\n\n"
|
|
388
|
+
)
|
|
389
|
+
resp += f" {self.message}\n"
|
|
390
|
+
resp += (
|
|
391
|
+
f"\n------------------- system cost: {self.time_cost:.3f} seconds\n\n"
|
|
392
|
+
)
|
|
393
|
+
else:
|
|
394
|
+
resp += f"[ User: ] ({self.created_at.strftime('%Y-%m-%d %H:%M:%S')} UTC) by {self.author_id}\n\n"
|
|
395
|
+
resp += f" {self.message}\n"
|
|
396
|
+
resp += f"\n------------------- user cost: {self.time_cost:.3f} seconds\n\n"
|
|
397
|
+
|
|
398
|
+
return resp
|
|
399
|
+
|
|
400
|
+
@classmethod
|
|
401
|
+
async def get(cls, chat_id: str) -> Optional["ChatMessage"]:
|
|
402
|
+
async with get_session() as db:
|
|
403
|
+
raw = await db.get(ChatMessageTable, chat_id)
|
|
404
|
+
if raw:
|
|
405
|
+
return ChatMessage.model_validate(raw)
|
|
406
|
+
return None
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
class ChatTable(Base):
|
|
410
|
+
"""Chat database table model."""
|
|
411
|
+
|
|
412
|
+
__tablename__ = "chats"
|
|
413
|
+
__table_args__ = (Index("ix_chats_agent_user", "agent_id", "user_id"),)
|
|
414
|
+
|
|
415
|
+
id = Column(
|
|
416
|
+
String,
|
|
417
|
+
primary_key=True,
|
|
418
|
+
)
|
|
419
|
+
agent_id = Column(
|
|
420
|
+
String,
|
|
421
|
+
nullable=False,
|
|
422
|
+
)
|
|
423
|
+
user_id = Column(
|
|
424
|
+
String,
|
|
425
|
+
nullable=False,
|
|
426
|
+
)
|
|
427
|
+
summary = Column(
|
|
428
|
+
String,
|
|
429
|
+
default="",
|
|
430
|
+
)
|
|
431
|
+
rounds = Column(
|
|
432
|
+
Integer,
|
|
433
|
+
default=0,
|
|
434
|
+
)
|
|
435
|
+
created_at = Column(
|
|
436
|
+
DateTime(timezone=True),
|
|
437
|
+
nullable=False,
|
|
438
|
+
server_default=func.now(),
|
|
439
|
+
)
|
|
440
|
+
updated_at = Column(
|
|
441
|
+
DateTime(timezone=True),
|
|
442
|
+
nullable=False,
|
|
443
|
+
server_default=func.now(),
|
|
444
|
+
onupdate=lambda: datetime.now(timezone.utc),
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
class ChatCreate(BaseModel):
|
|
449
|
+
"""Base model for creating chats with fields needed for creation."""
|
|
450
|
+
|
|
451
|
+
model_config = ConfigDict(from_attributes=True)
|
|
452
|
+
|
|
453
|
+
id: Annotated[
|
|
454
|
+
str,
|
|
455
|
+
Field(
|
|
456
|
+
default_factory=lambda: str(XID()),
|
|
457
|
+
description="Unique identifier for the chat",
|
|
458
|
+
),
|
|
459
|
+
]
|
|
460
|
+
agent_id: Annotated[str, Field(description="ID of the agent this chat belongs to")]
|
|
461
|
+
user_id: Annotated[str, Field(description="User ID of the chat")]
|
|
462
|
+
summary: Annotated[str, Field("", description="Summary of the chat")]
|
|
463
|
+
rounds: Annotated[int, Field(0, description="Number of rounds in the chat")]
|
|
464
|
+
|
|
465
|
+
async def save(self) -> "Chat":
|
|
466
|
+
"""Create a new chat in the database.
|
|
467
|
+
|
|
468
|
+
Returns:
|
|
469
|
+
Chat: The saved chat with all fields populated
|
|
470
|
+
"""
|
|
471
|
+
# Set timestamps
|
|
472
|
+
chat_record = ChatTable(**self.model_dump(exclude_unset=True))
|
|
473
|
+
|
|
474
|
+
async with get_session() as db:
|
|
475
|
+
db.add(chat_record)
|
|
476
|
+
await db.commit()
|
|
477
|
+
await db.refresh(chat_record)
|
|
478
|
+
|
|
479
|
+
# Create and return a full Chat instance
|
|
480
|
+
return Chat.model_validate(chat_record)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
class Chat(ChatCreate):
|
|
484
|
+
"""Chat model with all fields including server-generated ones."""
|
|
485
|
+
|
|
486
|
+
model_config = ConfigDict(
|
|
487
|
+
from_attributes=True,
|
|
488
|
+
json_encoders={datetime: lambda v: v.isoformat(timespec="milliseconds")},
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
created_at: Annotated[
|
|
492
|
+
datetime, Field(description="Timestamp when this chat was created")
|
|
493
|
+
]
|
|
494
|
+
updated_at: Annotated[
|
|
495
|
+
datetime, Field(description="Timestamp when this chat was updated")
|
|
496
|
+
]
|
|
497
|
+
|
|
498
|
+
@classmethod
|
|
499
|
+
async def get(cls, id: str) -> Optional["Chat"]:
|
|
500
|
+
"""Get a chat by its ID.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
id: ID of the chat to get
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
Chat if found, None otherwise
|
|
507
|
+
"""
|
|
508
|
+
async with get_session() as db:
|
|
509
|
+
chat_record = await db.get(ChatTable, id)
|
|
510
|
+
if chat_record:
|
|
511
|
+
return cls.model_validate(chat_record)
|
|
512
|
+
return None
|
|
513
|
+
|
|
514
|
+
async def delete(self):
|
|
515
|
+
"""Delete the chat from the database."""
|
|
516
|
+
async with get_session() as db:
|
|
517
|
+
chat_record = await db.get(ChatTable, self.id)
|
|
518
|
+
if chat_record:
|
|
519
|
+
await db.delete(chat_record)
|
|
520
|
+
await db.commit()
|
|
521
|
+
|
|
522
|
+
async def add_round(self):
|
|
523
|
+
"""Increment the number of rounds in the chat on the database server.
|
|
524
|
+
|
|
525
|
+
Uses a direct SQL UPDATE statement to increment the rounds counter
|
|
526
|
+
on the server side, avoiding potential race conditions.
|
|
527
|
+
"""
|
|
528
|
+
async with get_session() as db:
|
|
529
|
+
stmt = (
|
|
530
|
+
update(ChatTable)
|
|
531
|
+
.where(ChatTable.id == self.id)
|
|
532
|
+
.values(rounds=ChatTable.rounds + 1)
|
|
533
|
+
)
|
|
534
|
+
await db.execute(stmt)
|
|
535
|
+
await db.commit()
|
|
536
|
+
|
|
537
|
+
# Update local object
|
|
538
|
+
self.rounds += 1
|
|
539
|
+
|
|
540
|
+
async def update_summary(self, summary: str) -> "Chat":
|
|
541
|
+
"""Update the chat summary in the database.
|
|
542
|
+
|
|
543
|
+
Uses a direct SQL UPDATE statement to set the summary field.
|
|
544
|
+
|
|
545
|
+
Args:
|
|
546
|
+
summary: New summary text for the chat
|
|
547
|
+
|
|
548
|
+
Returns:
|
|
549
|
+
Chat: The updated chat instance
|
|
550
|
+
"""
|
|
551
|
+
async with get_session() as db:
|
|
552
|
+
stmt = (
|
|
553
|
+
update(ChatTable).where(ChatTable.id == self.id).values(summary=summary)
|
|
554
|
+
)
|
|
555
|
+
await db.execute(stmt)
|
|
556
|
+
await db.commit()
|
|
557
|
+
|
|
558
|
+
# Update local object
|
|
559
|
+
self.summary = summary
|
|
560
|
+
return self
|
|
561
|
+
|
|
562
|
+
@classmethod
|
|
563
|
+
async def get_by_agent_user(cls, agent_id: str, user_id: str) -> List["Chat"]:
|
|
564
|
+
"""Get all chats for a specific agent and user.
|
|
565
|
+
|
|
566
|
+
Args:
|
|
567
|
+
agent_id: ID of the agent
|
|
568
|
+
user_id: ID of the user
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
List of chats
|
|
572
|
+
"""
|
|
573
|
+
async with get_session() as db:
|
|
574
|
+
results = await db.scalars(
|
|
575
|
+
select(ChatTable)
|
|
576
|
+
.order_by(desc(ChatTable.updated_at))
|
|
577
|
+
.limit(10)
|
|
578
|
+
.where(ChatTable.agent_id == agent_id, ChatTable.user_id == user_id)
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
return [cls.model_validate(chat) for chat in results]
|