intentkit 0.5.0__py3-none-any.whl → 0.5.1__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.
- abstracts/__init__.py +0 -0
- abstracts/agent.py +60 -0
- abstracts/api.py +4 -0
- abstracts/engine.py +38 -0
- abstracts/exception.py +9 -0
- abstracts/graph.py +25 -0
- abstracts/skill.py +129 -0
- abstracts/twitter.py +54 -0
- clients/__init__.py +14 -0
- clients/cdp.py +53 -0
- clients/twitter.py +445 -0
- config/__init__.py +0 -0
- config/config.py +164 -0
- core/__init__.py +0 -0
- core/agent.py +191 -0
- core/api.py +40 -0
- core/client.py +45 -0
- core/credit.py +1767 -0
- core/engine.py +1018 -0
- core/node.py +223 -0
- core/prompt.py +58 -0
- core/skill.py +124 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.1.dist-info}/METADATA +1 -1
- intentkit-0.5.1.dist-info/RECORD +364 -0
- models/agent.py +1689 -0
- models/agent_data.py +810 -0
- models/agent_schema.json +733 -0
- models/app_setting.py +156 -0
- models/base.py +9 -0
- models/chat.py +581 -0
- models/conversation.py +286 -0
- models/credit.py +1406 -0
- models/db.py +120 -0
- models/db_mig.py +102 -0
- models/generator.py +347 -0
- models/llm.py +746 -0
- models/redis.py +132 -0
- models/skill.py +466 -0
- models/user.py +243 -0
- skills/__init__.py +12 -0
- skills/acolyt/__init__.py +83 -0
- skills/acolyt/acolyt.jpg +0 -0
- skills/acolyt/ask.py +128 -0
- skills/acolyt/base.py +28 -0
- skills/acolyt/schema.json +89 -0
- skills/aixbt/README.md +71 -0
- skills/aixbt/__init__.py +73 -0
- skills/aixbt/aixbt.jpg +0 -0
- skills/aixbt/base.py +21 -0
- skills/aixbt/projects.py +153 -0
- skills/aixbt/schema.json +99 -0
- skills/allora/__init__.py +83 -0
- skills/allora/allora.jpeg +0 -0
- skills/allora/base.py +28 -0
- skills/allora/price.py +130 -0
- skills/allora/schema.json +89 -0
- skills/base.py +174 -0
- skills/carv/README.md +95 -0
- skills/carv/__init__.py +121 -0
- skills/carv/base.py +183 -0
- skills/carv/carv.webp +0 -0
- skills/carv/fetch_news.py +92 -0
- skills/carv/onchain_query.py +164 -0
- skills/carv/schema.json +137 -0
- skills/carv/token_info_and_price.py +110 -0
- skills/cdp/__init__.py +137 -0
- skills/cdp/base.py +21 -0
- skills/cdp/cdp.png +0 -0
- skills/cdp/get_balance.py +81 -0
- skills/cdp/schema.json +473 -0
- skills/chainlist/README.md +38 -0
- skills/chainlist/__init__.py +54 -0
- skills/chainlist/base.py +21 -0
- skills/chainlist/chain_lookup.py +208 -0
- skills/chainlist/chainlist.png +0 -0
- skills/chainlist/schema.json +47 -0
- skills/common/__init__.py +82 -0
- skills/common/base.py +21 -0
- skills/common/common.jpg +0 -0
- skills/common/current_time.py +84 -0
- skills/common/schema.json +57 -0
- skills/cookiefun/README.md +121 -0
- skills/cookiefun/__init__.py +78 -0
- skills/cookiefun/base.py +41 -0
- skills/cookiefun/constants.py +18 -0
- skills/cookiefun/cookiefun.png +0 -0
- skills/cookiefun/get_account_details.py +171 -0
- skills/cookiefun/get_account_feed.py +282 -0
- skills/cookiefun/get_account_smart_followers.py +181 -0
- skills/cookiefun/get_sectors.py +128 -0
- skills/cookiefun/schema.json +155 -0
- skills/cookiefun/search_accounts.py +225 -0
- skills/cryptocompare/__init__.py +130 -0
- skills/cryptocompare/api.py +159 -0
- skills/cryptocompare/base.py +303 -0
- skills/cryptocompare/cryptocompare.png +0 -0
- skills/cryptocompare/fetch_news.py +96 -0
- skills/cryptocompare/fetch_price.py +99 -0
- skills/cryptocompare/fetch_top_exchanges.py +113 -0
- skills/cryptocompare/fetch_top_market_cap.py +109 -0
- skills/cryptocompare/fetch_top_volume.py +108 -0
- skills/cryptocompare/fetch_trading_signals.py +107 -0
- skills/cryptocompare/schema.json +168 -0
- skills/cryptopanic/__init__.py +108 -0
- skills/cryptopanic/base.py +51 -0
- skills/cryptopanic/cryptopanic.png +0 -0
- skills/cryptopanic/fetch_crypto_news.py +153 -0
- skills/cryptopanic/fetch_crypto_sentiment.py +136 -0
- skills/cryptopanic/schema.json +103 -0
- skills/dapplooker/README.md +92 -0
- skills/dapplooker/__init__.py +83 -0
- skills/dapplooker/base.py +26 -0
- skills/dapplooker/dapplooker.jpg +0 -0
- skills/dapplooker/dapplooker_token_data.py +476 -0
- skills/dapplooker/schema.json +91 -0
- skills/defillama/__init__.py +323 -0
- skills/defillama/api.py +315 -0
- skills/defillama/base.py +135 -0
- skills/defillama/coins/__init__.py +0 -0
- skills/defillama/coins/fetch_batch_historical_prices.py +116 -0
- skills/defillama/coins/fetch_block.py +98 -0
- skills/defillama/coins/fetch_current_prices.py +105 -0
- skills/defillama/coins/fetch_first_price.py +100 -0
- skills/defillama/coins/fetch_historical_prices.py +110 -0
- skills/defillama/coins/fetch_price_chart.py +109 -0
- skills/defillama/coins/fetch_price_percentage.py +93 -0
- skills/defillama/config/__init__.py +0 -0
- skills/defillama/config/chains.py +433 -0
- skills/defillama/defillama.jpeg +0 -0
- skills/defillama/fees/__init__.py +0 -0
- skills/defillama/fees/fetch_fees_overview.py +130 -0
- skills/defillama/schema.json +383 -0
- skills/defillama/stablecoins/__init__.py +0 -0
- skills/defillama/stablecoins/fetch_stablecoin_chains.py +100 -0
- skills/defillama/stablecoins/fetch_stablecoin_charts.py +129 -0
- skills/defillama/stablecoins/fetch_stablecoin_prices.py +83 -0
- skills/defillama/stablecoins/fetch_stablecoins.py +126 -0
- skills/defillama/tests/__init__.py +0 -0
- skills/defillama/tests/api_integration.test.py +192 -0
- skills/defillama/tests/api_unit.test.py +583 -0
- skills/defillama/tvl/__init__.py +0 -0
- skills/defillama/tvl/fetch_chain_historical_tvl.py +106 -0
- skills/defillama/tvl/fetch_chains.py +107 -0
- skills/defillama/tvl/fetch_historical_tvl.py +91 -0
- skills/defillama/tvl/fetch_protocol.py +207 -0
- skills/defillama/tvl/fetch_protocol_current_tvl.py +93 -0
- skills/defillama/tvl/fetch_protocols.py +196 -0
- skills/defillama/volumes/__init__.py +0 -0
- skills/defillama/volumes/fetch_dex_overview.py +157 -0
- skills/defillama/volumes/fetch_dex_summary.py +123 -0
- skills/defillama/volumes/fetch_options_overview.py +131 -0
- skills/defillama/yields/__init__.py +0 -0
- skills/defillama/yields/fetch_pool_chart.py +100 -0
- skills/defillama/yields/fetch_pools.py +126 -0
- skills/dexscreener/__init__.py +93 -0
- skills/dexscreener/base.py +133 -0
- skills/dexscreener/dexscreener.png +0 -0
- skills/dexscreener/model/__init__.py +0 -0
- skills/dexscreener/model/search_token_response.py +82 -0
- skills/dexscreener/schema.json +48 -0
- skills/dexscreener/search_token.py +321 -0
- skills/dune_analytics/__init__.py +103 -0
- skills/dune_analytics/base.py +46 -0
- skills/dune_analytics/dune.png +0 -0
- skills/dune_analytics/fetch_kol_buys.py +128 -0
- skills/dune_analytics/fetch_nation_metrics.py +237 -0
- skills/dune_analytics/schema.json +99 -0
- skills/elfa/README.md +100 -0
- skills/elfa/__init__.py +123 -0
- skills/elfa/base.py +28 -0
- skills/elfa/elfa.jpg +0 -0
- skills/elfa/mention.py +504 -0
- skills/elfa/schema.json +153 -0
- skills/elfa/stats.py +118 -0
- skills/elfa/tokens.py +126 -0
- skills/enso/README.md +75 -0
- skills/enso/__init__.py +114 -0
- skills/enso/abi/__init__.py +0 -0
- skills/enso/abi/approval.py +279 -0
- skills/enso/abi/erc20.py +14 -0
- skills/enso/abi/route.py +129 -0
- skills/enso/base.py +44 -0
- skills/enso/best_yield.py +286 -0
- skills/enso/enso.jpg +0 -0
- skills/enso/networks.py +105 -0
- skills/enso/prices.py +93 -0
- skills/enso/route.py +300 -0
- skills/enso/schema.json +212 -0
- skills/enso/tokens.py +223 -0
- skills/enso/wallet.py +381 -0
- skills/github/README.md +63 -0
- skills/github/__init__.py +54 -0
- skills/github/base.py +21 -0
- skills/github/github.jpg +0 -0
- skills/github/github_search.py +183 -0
- skills/github/schema.json +59 -0
- skills/heurist/__init__.py +143 -0
- skills/heurist/base.py +26 -0
- skills/heurist/heurist.png +0 -0
- skills/heurist/image_generation_animagine_xl.py +162 -0
- skills/heurist/image_generation_arthemy_comics.py +162 -0
- skills/heurist/image_generation_arthemy_real.py +162 -0
- skills/heurist/image_generation_braindance.py +162 -0
- skills/heurist/image_generation_cyber_realistic_xl.py +162 -0
- skills/heurist/image_generation_flux_1_dev.py +162 -0
- skills/heurist/image_generation_sdxl.py +161 -0
- skills/heurist/schema.json +196 -0
- skills/lifi/README.md +294 -0
- skills/lifi/__init__.py +141 -0
- skills/lifi/base.py +21 -0
- skills/lifi/lifi.png +0 -0
- skills/lifi/schema.json +89 -0
- skills/lifi/token_execute.py +472 -0
- skills/lifi/token_quote.py +190 -0
- skills/lifi/utils.py +656 -0
- skills/moralis/README.md +490 -0
- skills/moralis/__init__.py +110 -0
- skills/moralis/api.py +281 -0
- skills/moralis/base.py +55 -0
- skills/moralis/fetch_chain_portfolio.py +191 -0
- skills/moralis/fetch_nft_portfolio.py +284 -0
- skills/moralis/fetch_solana_portfolio.py +331 -0
- skills/moralis/fetch_wallet_portfolio.py +301 -0
- skills/moralis/moralis.png +0 -0
- skills/moralis/schema.json +156 -0
- skills/moralis/tests/__init__.py +0 -0
- skills/moralis/tests/test_wallet.py +511 -0
- skills/nation/__init__.py +62 -0
- skills/nation/base.py +31 -0
- skills/nation/nation.png +0 -0
- skills/nation/nft_check.py +106 -0
- skills/nation/schema.json +58 -0
- skills/openai/__init__.py +107 -0
- skills/openai/base.py +32 -0
- skills/openai/dalle_image_generation.py +128 -0
- skills/openai/gpt_image_generation.py +152 -0
- skills/openai/gpt_image_to_image.py +186 -0
- skills/openai/image_to_text.py +126 -0
- skills/openai/openai.png +0 -0
- skills/openai/schema.json +139 -0
- skills/portfolio/README.md +55 -0
- skills/portfolio/__init__.py +151 -0
- skills/portfolio/base.py +107 -0
- skills/portfolio/constants.py +9 -0
- skills/portfolio/moralis.png +0 -0
- skills/portfolio/schema.json +237 -0
- skills/portfolio/token_balances.py +155 -0
- skills/portfolio/wallet_approvals.py +102 -0
- skills/portfolio/wallet_defi_positions.py +80 -0
- skills/portfolio/wallet_history.py +155 -0
- skills/portfolio/wallet_net_worth.py +112 -0
- skills/portfolio/wallet_nfts.py +139 -0
- skills/portfolio/wallet_profitability.py +101 -0
- skills/portfolio/wallet_profitability_summary.py +91 -0
- skills/portfolio/wallet_stats.py +79 -0
- skills/portfolio/wallet_swaps.py +147 -0
- skills/skills.toml +103 -0
- skills/slack/__init__.py +98 -0
- skills/slack/base.py +55 -0
- skills/slack/get_channel.py +109 -0
- skills/slack/get_message.py +136 -0
- skills/slack/schedule_message.py +92 -0
- skills/slack/schema.json +135 -0
- skills/slack/send_message.py +81 -0
- skills/slack/slack.jpg +0 -0
- skills/system/__init__.py +90 -0
- skills/system/base.py +22 -0
- skills/system/read_agent_api_key.py +87 -0
- skills/system/regenerate_agent_api_key.py +77 -0
- skills/system/schema.json +53 -0
- skills/system/system.svg +76 -0
- skills/tavily/README.md +86 -0
- skills/tavily/__init__.py +91 -0
- skills/tavily/base.py +27 -0
- skills/tavily/schema.json +119 -0
- skills/tavily/tavily.jpg +0 -0
- skills/tavily/tavily_extract.py +147 -0
- skills/tavily/tavily_search.py +139 -0
- skills/token/README.md +89 -0
- skills/token/__init__.py +107 -0
- skills/token/base.py +154 -0
- skills/token/constants.py +9 -0
- skills/token/erc20_transfers.py +145 -0
- skills/token/moralis.png +0 -0
- skills/token/schema.json +141 -0
- skills/token/token_analytics.py +81 -0
- skills/token/token_price.py +132 -0
- skills/token/token_search.py +121 -0
- skills/twitter/__init__.py +146 -0
- skills/twitter/base.py +68 -0
- skills/twitter/follow_user.py +69 -0
- skills/twitter/get_mentions.py +124 -0
- skills/twitter/get_timeline.py +111 -0
- skills/twitter/get_user_by_username.py +84 -0
- skills/twitter/get_user_tweets.py +123 -0
- skills/twitter/like_tweet.py +65 -0
- skills/twitter/post_tweet.py +90 -0
- skills/twitter/reply_tweet.py +98 -0
- skills/twitter/retweet.py +76 -0
- skills/twitter/schema.json +258 -0
- skills/twitter/search_tweets.py +115 -0
- skills/twitter/twitter.png +0 -0
- skills/unrealspeech/__init__.py +55 -0
- skills/unrealspeech/base.py +21 -0
- skills/unrealspeech/schema.json +100 -0
- skills/unrealspeech/text_to_speech.py +177 -0
- skills/unrealspeech/unrealspeech.jpg +0 -0
- skills/venice_audio/__init__.py +106 -0
- skills/venice_audio/base.py +119 -0
- skills/venice_audio/input.py +41 -0
- skills/venice_audio/schema.json +152 -0
- skills/venice_audio/venice_audio.py +240 -0
- skills/venice_audio/venice_logo.jpg +0 -0
- skills/venice_image/README.md +119 -0
- skills/venice_image/__init__.py +154 -0
- skills/venice_image/api.py +138 -0
- skills/venice_image/base.py +188 -0
- skills/venice_image/config.py +35 -0
- skills/venice_image/image_enhance/README.md +119 -0
- skills/venice_image/image_enhance/__init__.py +0 -0
- skills/venice_image/image_enhance/image_enhance.py +80 -0
- skills/venice_image/image_enhance/image_enhance_base.py +23 -0
- skills/venice_image/image_enhance/image_enhance_input.py +40 -0
- skills/venice_image/image_generation/README.md +144 -0
- skills/venice_image/image_generation/__init__.py +0 -0
- skills/venice_image/image_generation/image_generation_base.py +117 -0
- skills/venice_image/image_generation/image_generation_fluently_xl.py +26 -0
- skills/venice_image/image_generation/image_generation_flux_dev.py +27 -0
- skills/venice_image/image_generation/image_generation_flux_dev_uncensored.py +26 -0
- skills/venice_image/image_generation/image_generation_input.py +158 -0
- skills/venice_image/image_generation/image_generation_lustify_sdxl.py +26 -0
- skills/venice_image/image_generation/image_generation_pony_realism.py +26 -0
- skills/venice_image/image_generation/image_generation_stable_diffusion_3_5.py +28 -0
- skills/venice_image/image_generation/image_generation_venice_sd35.py +28 -0
- skills/venice_image/image_upscale/README.md +111 -0
- skills/venice_image/image_upscale/__init__.py +0 -0
- skills/venice_image/image_upscale/image_upscale.py +90 -0
- skills/venice_image/image_upscale/image_upscale_base.py +23 -0
- skills/venice_image/image_upscale/image_upscale_input.py +22 -0
- skills/venice_image/image_vision/README.md +112 -0
- skills/venice_image/image_vision/__init__.py +0 -0
- skills/venice_image/image_vision/image_vision.py +100 -0
- skills/venice_image/image_vision/image_vision_base.py +17 -0
- skills/venice_image/image_vision/image_vision_input.py +9 -0
- skills/venice_image/schema.json +267 -0
- skills/venice_image/utils.py +78 -0
- skills/venice_image/venice_image.jpg +0 -0
- skills/web_scraper/README.md +82 -0
- skills/web_scraper/__init__.py +92 -0
- skills/web_scraper/base.py +21 -0
- skills/web_scraper/langchain.png +0 -0
- skills/web_scraper/schema.json +115 -0
- skills/web_scraper/scrape_and_index.py +327 -0
- utils/__init__.py +1 -0
- utils/chain.py +436 -0
- utils/error.py +134 -0
- utils/logging.py +70 -0
- utils/middleware.py +61 -0
- utils/random.py +16 -0
- utils/s3.py +267 -0
- utils/slack_alert.py +79 -0
- utils/tx.py +37 -0
- intentkit-0.5.0.dist-info/RECORD +0 -4
- {intentkit-0.5.0.dist-info → intentkit-0.5.1.dist-info}/WHEEL +0 -0
- {intentkit-0.5.0.dist-info → intentkit-0.5.1.dist-info}/licenses/LICENSE +0 -0
models/conversation.py
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
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]
|