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/credit.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from datetime import
|
|
2
|
+
from datetime import UTC, datetime
|
|
3
3
|
from decimal import ROUND_HALF_UP, Decimal
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import Annotated, Any
|
|
5
|
+
from typing import Annotated, Any
|
|
6
6
|
|
|
7
7
|
from epyxid import XID
|
|
8
8
|
from fastapi import HTTPException
|
|
9
9
|
from intentkit.models.app_setting import AppSetting
|
|
10
10
|
from intentkit.models.base import Base
|
|
11
11
|
from intentkit.models.db import get_session
|
|
12
|
+
from intentkit.utils.error import IntentKitAPIError
|
|
12
13
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
13
14
|
from sqlalchemy import (
|
|
14
15
|
ARRAY,
|
|
@@ -26,6 +27,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
26
27
|
|
|
27
28
|
logger = logging.getLogger(__name__)
|
|
28
29
|
|
|
30
|
+
# Precision constant for 4 decimal places
|
|
31
|
+
FOURPLACES = Decimal("0.0001")
|
|
32
|
+
|
|
29
33
|
|
|
30
34
|
class CreditType(str, Enum):
|
|
31
35
|
"""Credit type is used in db column names, do not change it."""
|
|
@@ -57,6 +61,7 @@ DEFAULT_PLATFORM_ACCOUNT_VOICE = "platform_voice"
|
|
|
57
61
|
DEFAULT_PLATFORM_ACCOUNT_KNOWLEDGE = "platform_knowledge"
|
|
58
62
|
DEFAULT_PLATFORM_ACCOUNT_FEE = "platform_fee"
|
|
59
63
|
DEFAULT_PLATFORM_ACCOUNT_DEV = "platform_dev"
|
|
64
|
+
DEFAULT_PLATFORM_ACCOUNT_WITHDRAW = "platform_withdraw"
|
|
60
65
|
|
|
61
66
|
|
|
62
67
|
class CreditAccountTable(Base):
|
|
@@ -114,6 +119,47 @@ class CreditAccountTable(Base):
|
|
|
114
119
|
String,
|
|
115
120
|
nullable=True,
|
|
116
121
|
)
|
|
122
|
+
# Total statistics fields
|
|
123
|
+
total_income = Column(
|
|
124
|
+
Numeric(22, 4),
|
|
125
|
+
default=0,
|
|
126
|
+
nullable=False,
|
|
127
|
+
)
|
|
128
|
+
total_free_income = Column(
|
|
129
|
+
Numeric(22, 4),
|
|
130
|
+
default=0,
|
|
131
|
+
nullable=False,
|
|
132
|
+
)
|
|
133
|
+
total_reward_income = Column(
|
|
134
|
+
Numeric(22, 4),
|
|
135
|
+
default=0,
|
|
136
|
+
nullable=False,
|
|
137
|
+
)
|
|
138
|
+
total_permanent_income = Column(
|
|
139
|
+
Numeric(22, 4),
|
|
140
|
+
default=0,
|
|
141
|
+
nullable=False,
|
|
142
|
+
)
|
|
143
|
+
total_expense = Column(
|
|
144
|
+
Numeric(22, 4),
|
|
145
|
+
default=0,
|
|
146
|
+
nullable=False,
|
|
147
|
+
)
|
|
148
|
+
total_free_expense = Column(
|
|
149
|
+
Numeric(22, 4),
|
|
150
|
+
default=0,
|
|
151
|
+
nullable=False,
|
|
152
|
+
)
|
|
153
|
+
total_reward_expense = Column(
|
|
154
|
+
Numeric(22, 4),
|
|
155
|
+
default=0,
|
|
156
|
+
nullable=False,
|
|
157
|
+
)
|
|
158
|
+
total_permanent_expense = Column(
|
|
159
|
+
Numeric(22, 4),
|
|
160
|
+
default=0,
|
|
161
|
+
nullable=False,
|
|
162
|
+
)
|
|
117
163
|
created_at = Column(
|
|
118
164
|
DateTime(timezone=True),
|
|
119
165
|
nullable=False,
|
|
@@ -123,7 +169,7 @@ class CreditAccountTable(Base):
|
|
|
123
169
|
DateTime(timezone=True),
|
|
124
170
|
nullable=False,
|
|
125
171
|
server_default=func.now(),
|
|
126
|
-
onupdate=lambda: datetime.now(
|
|
172
|
+
onupdate=lambda: datetime.now(UTC),
|
|
127
173
|
)
|
|
128
174
|
|
|
129
175
|
|
|
@@ -175,17 +221,74 @@ class CreditAccount(BaseModel):
|
|
|
175
221
|
Field(default=Decimal("0"), description="Credits added through top-ups"),
|
|
176
222
|
]
|
|
177
223
|
income_at: Annotated[
|
|
178
|
-
|
|
224
|
+
datetime | None,
|
|
179
225
|
Field(None, description="Timestamp of the last income transaction"),
|
|
180
226
|
]
|
|
181
227
|
expense_at: Annotated[
|
|
182
|
-
|
|
228
|
+
datetime | None,
|
|
183
229
|
Field(None, description="Timestamp of the last expense transaction"),
|
|
184
230
|
]
|
|
185
231
|
last_event_id: Annotated[
|
|
186
|
-
|
|
232
|
+
str | None,
|
|
187
233
|
Field(None, description="ID of the last event that modified this account"),
|
|
188
234
|
]
|
|
235
|
+
# Total statistics fields
|
|
236
|
+
total_income: Annotated[
|
|
237
|
+
Decimal,
|
|
238
|
+
Field(
|
|
239
|
+
default=Decimal("0"),
|
|
240
|
+
description="Total income from all credit transactions",
|
|
241
|
+
),
|
|
242
|
+
]
|
|
243
|
+
total_free_income: Annotated[
|
|
244
|
+
Decimal,
|
|
245
|
+
Field(
|
|
246
|
+
default=Decimal("0"),
|
|
247
|
+
description="Total income from free credit transactions",
|
|
248
|
+
),
|
|
249
|
+
]
|
|
250
|
+
total_reward_income: Annotated[
|
|
251
|
+
Decimal,
|
|
252
|
+
Field(
|
|
253
|
+
default=Decimal("0"),
|
|
254
|
+
description="Total income from reward credit transactions",
|
|
255
|
+
),
|
|
256
|
+
]
|
|
257
|
+
total_permanent_income: Annotated[
|
|
258
|
+
Decimal,
|
|
259
|
+
Field(
|
|
260
|
+
default=Decimal("0"),
|
|
261
|
+
description="Total income from permanent credit transactions",
|
|
262
|
+
),
|
|
263
|
+
]
|
|
264
|
+
total_expense: Annotated[
|
|
265
|
+
Decimal,
|
|
266
|
+
Field(
|
|
267
|
+
default=Decimal("0"),
|
|
268
|
+
description="Total expense from all credit transactions",
|
|
269
|
+
),
|
|
270
|
+
]
|
|
271
|
+
total_free_expense: Annotated[
|
|
272
|
+
Decimal,
|
|
273
|
+
Field(
|
|
274
|
+
default=Decimal("0"),
|
|
275
|
+
description="Total expense from free credit transactions",
|
|
276
|
+
),
|
|
277
|
+
]
|
|
278
|
+
total_reward_expense: Annotated[
|
|
279
|
+
Decimal,
|
|
280
|
+
Field(
|
|
281
|
+
default=Decimal("0"),
|
|
282
|
+
description="Total expense from reward credit transactions",
|
|
283
|
+
),
|
|
284
|
+
]
|
|
285
|
+
total_permanent_expense: Annotated[
|
|
286
|
+
Decimal,
|
|
287
|
+
Field(
|
|
288
|
+
default=Decimal("0"),
|
|
289
|
+
description="Total expense from permanent credit transactions",
|
|
290
|
+
),
|
|
291
|
+
]
|
|
189
292
|
created_at: Annotated[
|
|
190
293
|
datetime, Field(description="Timestamp when this account was created")
|
|
191
294
|
]
|
|
@@ -194,14 +297,26 @@ class CreditAccount(BaseModel):
|
|
|
194
297
|
]
|
|
195
298
|
|
|
196
299
|
@field_validator(
|
|
197
|
-
"free_quota",
|
|
300
|
+
"free_quota",
|
|
301
|
+
"refill_amount",
|
|
302
|
+
"free_credits",
|
|
303
|
+
"reward_credits",
|
|
304
|
+
"credits",
|
|
305
|
+
"total_income",
|
|
306
|
+
"total_free_income",
|
|
307
|
+
"total_reward_income",
|
|
308
|
+
"total_permanent_income",
|
|
309
|
+
"total_expense",
|
|
310
|
+
"total_free_expense",
|
|
311
|
+
"total_reward_expense",
|
|
312
|
+
"total_permanent_expense",
|
|
198
313
|
)
|
|
199
314
|
@classmethod
|
|
200
315
|
def round_decimal(cls, v: Any) -> Decimal:
|
|
201
316
|
"""Round decimal values to 4 decimal places."""
|
|
202
317
|
if isinstance(v, Decimal):
|
|
203
318
|
return v.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
204
|
-
elif isinstance(v,
|
|
319
|
+
elif isinstance(v, int | float):
|
|
205
320
|
return Decimal(str(v)).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
206
321
|
return v
|
|
207
322
|
|
|
@@ -233,7 +348,11 @@ class CreditAccount(BaseModel):
|
|
|
233
348
|
)
|
|
234
349
|
result = await session.scalar(stmt)
|
|
235
350
|
if not result:
|
|
236
|
-
raise
|
|
351
|
+
raise IntentKitAPIError(
|
|
352
|
+
status_code=404,
|
|
353
|
+
key="CreditAccountNotFound",
|
|
354
|
+
message="Credit account not found",
|
|
355
|
+
)
|
|
237
356
|
return cls.model_validate(result)
|
|
238
357
|
|
|
239
358
|
@classmethod
|
|
@@ -294,19 +413,38 @@ class CreditAccount(BaseModel):
|
|
|
294
413
|
owner_id: str,
|
|
295
414
|
credit_type: CreditType,
|
|
296
415
|
amount: Decimal,
|
|
297
|
-
event_id:
|
|
416
|
+
event_id: str | None = None,
|
|
298
417
|
) -> "CreditAccount":
|
|
299
418
|
"""Deduct credits from an account. Not checking balance"""
|
|
300
419
|
# check first, create if not exists
|
|
301
420
|
await cls.get_or_create_in_session(session, owner_type, owner_id)
|
|
302
421
|
|
|
422
|
+
# Quantize the amount to ensure proper precision
|
|
423
|
+
quantized_amount = amount.quantize(FOURPLACES, rounding=ROUND_HALF_UP)
|
|
303
424
|
values_dict = {
|
|
304
|
-
credit_type.value: getattr(CreditAccountTable, credit_type.value)
|
|
305
|
-
|
|
425
|
+
credit_type.value: getattr(CreditAccountTable, credit_type.value)
|
|
426
|
+
- quantized_amount,
|
|
427
|
+
"expense_at": datetime.now(UTC),
|
|
428
|
+
# Update total expense statistics
|
|
429
|
+
"total_expense": CreditAccountTable.total_expense + quantized_amount,
|
|
306
430
|
}
|
|
307
431
|
if event_id:
|
|
308
432
|
values_dict["last_event_id"] = event_id
|
|
309
433
|
|
|
434
|
+
# Update corresponding statistics fields based on credit type
|
|
435
|
+
if credit_type == CreditType.FREE:
|
|
436
|
+
values_dict["total_free_expense"] = (
|
|
437
|
+
CreditAccountTable.total_free_expense + quantized_amount
|
|
438
|
+
)
|
|
439
|
+
elif credit_type == CreditType.REWARD:
|
|
440
|
+
values_dict["total_reward_expense"] = (
|
|
441
|
+
CreditAccountTable.total_reward_expense + quantized_amount
|
|
442
|
+
)
|
|
443
|
+
elif credit_type == CreditType.PERMANENT:
|
|
444
|
+
values_dict["total_permanent_expense"] = (
|
|
445
|
+
CreditAccountTable.total_permanent_expense + quantized_amount
|
|
446
|
+
)
|
|
447
|
+
|
|
310
448
|
stmt = (
|
|
311
449
|
update(CreditAccountTable)
|
|
312
450
|
.where(
|
|
@@ -318,7 +456,11 @@ class CreditAccount(BaseModel):
|
|
|
318
456
|
)
|
|
319
457
|
res = await session.scalar(stmt)
|
|
320
458
|
if not res:
|
|
321
|
-
raise
|
|
459
|
+
raise IntentKitAPIError(
|
|
460
|
+
status_code=500,
|
|
461
|
+
key="CreditExpenseFailed",
|
|
462
|
+
message="Failed to expense credits",
|
|
463
|
+
)
|
|
322
464
|
return cls.model_validate(res)
|
|
323
465
|
|
|
324
466
|
@classmethod
|
|
@@ -328,8 +470,8 @@ class CreditAccount(BaseModel):
|
|
|
328
470
|
owner_type: OwnerType,
|
|
329
471
|
owner_id: str,
|
|
330
472
|
amount: Decimal,
|
|
331
|
-
event_id:
|
|
332
|
-
) ->
|
|
473
|
+
event_id: str | None = None,
|
|
474
|
+
) -> tuple["CreditAccount", dict[CreditType, Decimal]]:
|
|
333
475
|
"""Expense credits and return account and credit type.
|
|
334
476
|
We are not checking balance here, since a conversation may have
|
|
335
477
|
multiple expenses, we can't interrupt the conversation.
|
|
@@ -348,31 +490,62 @@ class CreditAccount(BaseModel):
|
|
|
348
490
|
else:
|
|
349
491
|
if account.free_credits > 0:
|
|
350
492
|
details[CreditType.FREE] = account.free_credits
|
|
351
|
-
amount_left
|
|
493
|
+
amount_left = (amount_left - account.free_credits).quantize(
|
|
494
|
+
FOURPLACES, rounding=ROUND_HALF_UP
|
|
495
|
+
)
|
|
352
496
|
if amount_left <= account.reward_credits:
|
|
353
497
|
details[CreditType.REWARD] = amount_left
|
|
354
498
|
amount_left = Decimal("0")
|
|
355
499
|
else:
|
|
356
500
|
if account.reward_credits > 0:
|
|
357
501
|
details[CreditType.REWARD] = account.reward_credits
|
|
358
|
-
amount_left
|
|
502
|
+
amount_left = (amount_left - account.reward_credits).quantize(
|
|
503
|
+
FOURPLACES, rounding=ROUND_HALF_UP
|
|
504
|
+
)
|
|
359
505
|
details[CreditType.PERMANENT] = amount_left
|
|
360
506
|
|
|
361
507
|
# Create values dict based on what's in details, defaulting to 0 for missing keys
|
|
362
508
|
values_dict = {
|
|
363
|
-
"expense_at": datetime.now(
|
|
509
|
+
"expense_at": datetime.now(UTC),
|
|
364
510
|
}
|
|
365
511
|
if event_id:
|
|
366
512
|
values_dict["last_event_id"] = event_id
|
|
367
513
|
|
|
514
|
+
# Calculate total expense for statistics
|
|
515
|
+
total_expense_amount = Decimal("0")
|
|
516
|
+
|
|
368
517
|
# Add credit type values only if they exist in details
|
|
369
518
|
for credit_type in [CreditType.FREE, CreditType.REWARD, CreditType.PERMANENT]:
|
|
370
519
|
if credit_type in details:
|
|
520
|
+
# Quantize the amount to ensure proper precision
|
|
521
|
+
quantized_amount = details[credit_type].quantize(
|
|
522
|
+
FOURPLACES, rounding=ROUND_HALF_UP
|
|
523
|
+
)
|
|
371
524
|
values_dict[credit_type.value] = (
|
|
372
|
-
getattr(CreditAccountTable, credit_type.value)
|
|
373
|
-
- details[credit_type]
|
|
525
|
+
getattr(CreditAccountTable, credit_type.value) - quantized_amount
|
|
374
526
|
)
|
|
375
527
|
|
|
528
|
+
# Update corresponding statistics fields
|
|
529
|
+
total_expense_amount += quantized_amount
|
|
530
|
+
if credit_type == CreditType.FREE:
|
|
531
|
+
values_dict["total_free_expense"] = (
|
|
532
|
+
CreditAccountTable.total_free_expense + quantized_amount
|
|
533
|
+
)
|
|
534
|
+
elif credit_type == CreditType.REWARD:
|
|
535
|
+
values_dict["total_reward_expense"] = (
|
|
536
|
+
CreditAccountTable.total_reward_expense + quantized_amount
|
|
537
|
+
)
|
|
538
|
+
elif credit_type == CreditType.PERMANENT:
|
|
539
|
+
values_dict["total_permanent_expense"] = (
|
|
540
|
+
CreditAccountTable.total_permanent_expense + quantized_amount
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
# Update total expense if there was any expense
|
|
544
|
+
if total_expense_amount > 0:
|
|
545
|
+
values_dict["total_expense"] = (
|
|
546
|
+
CreditAccountTable.total_expense + total_expense_amount
|
|
547
|
+
)
|
|
548
|
+
|
|
376
549
|
stmt = (
|
|
377
550
|
update(CreditAccountTable)
|
|
378
551
|
.where(
|
|
@@ -384,7 +557,11 @@ class CreditAccount(BaseModel):
|
|
|
384
557
|
)
|
|
385
558
|
res = await session.scalar(stmt)
|
|
386
559
|
if not res:
|
|
387
|
-
raise
|
|
560
|
+
raise IntentKitAPIError(
|
|
561
|
+
status_code=500,
|
|
562
|
+
key="CreditExpenseFailed",
|
|
563
|
+
message="Failed to expense credits",
|
|
564
|
+
)
|
|
388
565
|
return cls.model_validate(res), details
|
|
389
566
|
|
|
390
567
|
def has_sufficient_credits(self, amount: Decimal) -> bool:
|
|
@@ -404,20 +581,51 @@ class CreditAccount(BaseModel):
|
|
|
404
581
|
session: AsyncSession,
|
|
405
582
|
owner_type: OwnerType,
|
|
406
583
|
owner_id: str,
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
event_id: Optional[str] = None,
|
|
584
|
+
amount_details: dict[CreditType, Decimal],
|
|
585
|
+
event_id: str | None = None,
|
|
410
586
|
) -> "CreditAccount":
|
|
411
587
|
# check first, create if not exists
|
|
412
588
|
await cls.get_or_create_in_session(session, owner_type, owner_id)
|
|
413
589
|
# income
|
|
414
590
|
values_dict = {
|
|
415
|
-
|
|
416
|
-
"income_at": datetime.now(timezone.utc),
|
|
591
|
+
"income_at": datetime.now(UTC),
|
|
417
592
|
}
|
|
418
593
|
if event_id:
|
|
419
594
|
values_dict["last_event_id"] = event_id
|
|
420
595
|
|
|
596
|
+
# Calculate total income for statistics
|
|
597
|
+
total_income_amount = Decimal("0")
|
|
598
|
+
|
|
599
|
+
# Add credit type values based on amount_details
|
|
600
|
+
for credit_type, amount in amount_details.items():
|
|
601
|
+
if amount > 0:
|
|
602
|
+
# Quantize the amount to ensure 4 decimal places precision
|
|
603
|
+
quantized_amount = amount.quantize(FOURPLACES, rounding=ROUND_HALF_UP)
|
|
604
|
+
values_dict[credit_type.value] = (
|
|
605
|
+
getattr(CreditAccountTable, credit_type.value) + quantized_amount
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
# Update corresponding statistics fields
|
|
609
|
+
total_income_amount += quantized_amount
|
|
610
|
+
if credit_type == CreditType.FREE:
|
|
611
|
+
values_dict["total_free_income"] = (
|
|
612
|
+
CreditAccountTable.total_free_income + quantized_amount
|
|
613
|
+
)
|
|
614
|
+
elif credit_type == CreditType.REWARD:
|
|
615
|
+
values_dict["total_reward_income"] = (
|
|
616
|
+
CreditAccountTable.total_reward_income + quantized_amount
|
|
617
|
+
)
|
|
618
|
+
elif credit_type == CreditType.PERMANENT:
|
|
619
|
+
values_dict["total_permanent_income"] = (
|
|
620
|
+
CreditAccountTable.total_permanent_income + quantized_amount
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
# Update total income if there was any income
|
|
624
|
+
if total_income_amount > 0:
|
|
625
|
+
values_dict["total_income"] = (
|
|
626
|
+
CreditAccountTable.total_income + total_income_amount
|
|
627
|
+
)
|
|
628
|
+
|
|
421
629
|
stmt = (
|
|
422
630
|
update(CreditAccountTable)
|
|
423
631
|
.where(
|
|
@@ -438,8 +646,8 @@ class CreditAccount(BaseModel):
|
|
|
438
646
|
session: AsyncSession,
|
|
439
647
|
owner_type: OwnerType,
|
|
440
648
|
owner_id: str,
|
|
441
|
-
free_quota:
|
|
442
|
-
refill_amount:
|
|
649
|
+
free_quota: Decimal | None = None,
|
|
650
|
+
refill_amount: Decimal | None = None,
|
|
443
651
|
) -> "CreditAccount":
|
|
444
652
|
"""Get an existing credit account or create a new one if it doesn't exist.
|
|
445
653
|
|
|
@@ -479,9 +687,19 @@ class CreditAccount(BaseModel):
|
|
|
479
687
|
free_credits=free_quota,
|
|
480
688
|
reward_credits=0.0,
|
|
481
689
|
credits=0.0,
|
|
482
|
-
income_at=datetime.now(
|
|
690
|
+
income_at=datetime.now(UTC),
|
|
483
691
|
expense_at=None,
|
|
484
692
|
last_event_id=event_id if owner_type == OwnerType.USER else None,
|
|
693
|
+
# Initialize new statistics fields
|
|
694
|
+
# For USER accounts, initial free_quota counts as income
|
|
695
|
+
total_income=free_quota,
|
|
696
|
+
total_free_income=free_quota,
|
|
697
|
+
total_reward_income=0.0,
|
|
698
|
+
total_permanent_income=0.0,
|
|
699
|
+
total_expense=0.0,
|
|
700
|
+
total_free_expense=0.0,
|
|
701
|
+
total_reward_expense=0.0,
|
|
702
|
+
total_permanent_expense=0.0,
|
|
485
703
|
)
|
|
486
704
|
# Platform virtual accounts have fixed IDs, same as owner_id
|
|
487
705
|
if owner_type == OwnerType.PLATFORM:
|
|
@@ -515,6 +733,7 @@ class CreditAccount(BaseModel):
|
|
|
515
733
|
balance_after=free_quota,
|
|
516
734
|
base_amount=free_quota,
|
|
517
735
|
base_original_amount=free_quota,
|
|
736
|
+
base_free_amount=free_quota,
|
|
518
737
|
free_amount=free_quota, # Set free_amount since this is a free credit refill
|
|
519
738
|
reward_amount=Decimal("0"), # No reward credits involved
|
|
520
739
|
permanent_amount=Decimal("0"), # No permanent credits involved
|
|
@@ -530,10 +749,13 @@ class CreditAccount(BaseModel):
|
|
|
530
749
|
id=str(XID()),
|
|
531
750
|
account_id=account.id,
|
|
532
751
|
event_id=event_id,
|
|
533
|
-
tx_type=TransactionType.
|
|
752
|
+
tx_type=TransactionType.REFILL,
|
|
534
753
|
credit_debit=CreditDebit.CREDIT,
|
|
535
754
|
change_amount=free_quota,
|
|
536
755
|
credit_type=CreditType.FREE,
|
|
756
|
+
free_amount=free_quota,
|
|
757
|
+
reward_amount=Decimal("0"),
|
|
758
|
+
permanent_amount=Decimal("0"),
|
|
537
759
|
)
|
|
538
760
|
session.add(user_tx)
|
|
539
761
|
|
|
@@ -546,6 +768,9 @@ class CreditAccount(BaseModel):
|
|
|
546
768
|
credit_debit=CreditDebit.DEBIT,
|
|
547
769
|
change_amount=free_quota,
|
|
548
770
|
credit_type=CreditType.FREE,
|
|
771
|
+
free_amount=free_quota,
|
|
772
|
+
reward_amount=Decimal("0"),
|
|
773
|
+
permanent_amount=Decimal("0"),
|
|
549
774
|
)
|
|
550
775
|
session.add(platform_tx)
|
|
551
776
|
|
|
@@ -556,8 +781,8 @@ class CreditAccount(BaseModel):
|
|
|
556
781
|
cls,
|
|
557
782
|
session: AsyncSession,
|
|
558
783
|
user_id: str,
|
|
559
|
-
free_quota:
|
|
560
|
-
refill_amount:
|
|
784
|
+
free_quota: Decimal | None = None,
|
|
785
|
+
refill_amount: Decimal | None = None,
|
|
561
786
|
upstream_tx_id: str = "",
|
|
562
787
|
note: str = "",
|
|
563
788
|
) -> "CreditAccount":
|
|
@@ -609,6 +834,10 @@ class CreditAccount(BaseModel):
|
|
|
609
834
|
if not note:
|
|
610
835
|
raise ValueError("Quota update requires a note explaining the reason")
|
|
611
836
|
|
|
837
|
+
# Quantize values to ensure proper precision (4 decimal places)
|
|
838
|
+
free_quota = free_quota.quantize(FOURPLACES, rounding=ROUND_HALF_UP)
|
|
839
|
+
refill_amount = refill_amount.quantize(FOURPLACES, rounding=ROUND_HALF_UP)
|
|
840
|
+
|
|
612
841
|
# Update the free_quota field
|
|
613
842
|
stmt = (
|
|
614
843
|
update(CreditAccountTable)
|
|
@@ -650,6 +879,7 @@ class EventType(str, Enum):
|
|
|
650
879
|
REFUND = "refund"
|
|
651
880
|
ADJUSTMENT = "adjustment"
|
|
652
881
|
REFILL = "refill"
|
|
882
|
+
WITHDRAW = "withdraw"
|
|
653
883
|
# Sync with RewardType values
|
|
654
884
|
REWARD = "reward"
|
|
655
885
|
EVENT_REWARD = "event_reward"
|
|
@@ -794,6 +1024,21 @@ class CreditEventTable(Base):
|
|
|
794
1024
|
default=0,
|
|
795
1025
|
nullable=True,
|
|
796
1026
|
)
|
|
1027
|
+
base_free_amount = Column(
|
|
1028
|
+
Numeric(22, 4),
|
|
1029
|
+
default=0,
|
|
1030
|
+
nullable=True,
|
|
1031
|
+
)
|
|
1032
|
+
base_reward_amount = Column(
|
|
1033
|
+
Numeric(22, 4),
|
|
1034
|
+
default=0,
|
|
1035
|
+
nullable=True,
|
|
1036
|
+
)
|
|
1037
|
+
base_permanent_amount = Column(
|
|
1038
|
+
Numeric(22, 4),
|
|
1039
|
+
default=0,
|
|
1040
|
+
nullable=True,
|
|
1041
|
+
)
|
|
797
1042
|
fee_platform_amount = Column(
|
|
798
1043
|
Numeric(22, 4),
|
|
799
1044
|
default=0,
|
|
@@ -902,34 +1147,34 @@ class CreditEvent(BaseModel):
|
|
|
902
1147
|
]
|
|
903
1148
|
event_type: Annotated[EventType, Field(description="Type of the event")]
|
|
904
1149
|
user_id: Annotated[
|
|
905
|
-
|
|
1150
|
+
str | None, Field(None, description="ID of the user if applicable")
|
|
906
1151
|
]
|
|
907
1152
|
upstream_type: Annotated[
|
|
908
1153
|
UpstreamType, Field(description="Type of upstream transaction")
|
|
909
1154
|
]
|
|
910
1155
|
upstream_tx_id: Annotated[str, Field(description="Upstream transaction ID if any")]
|
|
911
1156
|
agent_id: Annotated[
|
|
912
|
-
|
|
1157
|
+
str | None, Field(None, description="ID of the agent if applicable")
|
|
913
1158
|
]
|
|
914
1159
|
agent_wallet_address: Annotated[
|
|
915
|
-
|
|
1160
|
+
str | None,
|
|
916
1161
|
Field(None, description="Wallet address of the agent if applicable"),
|
|
917
1162
|
]
|
|
918
1163
|
start_message_id: Annotated[
|
|
919
|
-
|
|
1164
|
+
str | None,
|
|
920
1165
|
Field(None, description="ID of the starting message if applicable"),
|
|
921
1166
|
]
|
|
922
1167
|
message_id: Annotated[
|
|
923
|
-
|
|
1168
|
+
str | None, Field(None, description="ID of the message if applicable")
|
|
924
1169
|
]
|
|
925
1170
|
model: Annotated[
|
|
926
|
-
|
|
1171
|
+
str | None, Field(None, description="LLM model used if applicable")
|
|
927
1172
|
]
|
|
928
1173
|
skill_call_id: Annotated[
|
|
929
|
-
|
|
1174
|
+
str | None, Field(None, description="ID of the skill call if applicable")
|
|
930
1175
|
]
|
|
931
1176
|
skill_name: Annotated[
|
|
932
|
-
|
|
1177
|
+
str | None, Field(None, description="Name of the skill if applicable")
|
|
933
1178
|
]
|
|
934
1179
|
direction: Annotated[Direction, Field(description="Direction of the credit flow")]
|
|
935
1180
|
total_amount: Annotated[
|
|
@@ -941,11 +1186,11 @@ class CreditEvent(BaseModel):
|
|
|
941
1186
|
]
|
|
942
1187
|
credit_type: Annotated[CreditType, Field(description="Type of credits involved")]
|
|
943
1188
|
credit_types: Annotated[
|
|
944
|
-
|
|
1189
|
+
list[CreditType] | None,
|
|
945
1190
|
Field(default=None, description="Array of credit types involved"),
|
|
946
1191
|
]
|
|
947
1192
|
balance_after: Annotated[
|
|
948
|
-
|
|
1193
|
+
Decimal | None,
|
|
949
1194
|
Field(None, description="Account total balance after the transaction"),
|
|
950
1195
|
]
|
|
951
1196
|
base_amount: Annotated[
|
|
@@ -953,103 +1198,115 @@ class CreditEvent(BaseModel):
|
|
|
953
1198
|
Field(default=Decimal("0"), description="Base amount of credits involved"),
|
|
954
1199
|
]
|
|
955
1200
|
base_discount_amount: Annotated[
|
|
956
|
-
|
|
1201
|
+
Decimal | None,
|
|
957
1202
|
Field(default=Decimal("0"), description="Base discount amount"),
|
|
958
1203
|
]
|
|
959
1204
|
base_original_amount: Annotated[
|
|
960
|
-
|
|
1205
|
+
Decimal | None,
|
|
961
1206
|
Field(default=Decimal("0"), description="Base original amount"),
|
|
962
1207
|
]
|
|
963
1208
|
base_llm_amount: Annotated[
|
|
964
|
-
|
|
1209
|
+
Decimal | None,
|
|
965
1210
|
Field(default=Decimal("0"), description="Base LLM cost amount"),
|
|
966
1211
|
]
|
|
967
1212
|
base_skill_amount: Annotated[
|
|
968
|
-
|
|
1213
|
+
Decimal | None,
|
|
969
1214
|
Field(default=Decimal("0"), description="Base skill cost amount"),
|
|
970
1215
|
]
|
|
1216
|
+
base_free_amount: Annotated[
|
|
1217
|
+
Decimal | None,
|
|
1218
|
+
Field(default=Decimal("0"), description="Base free credit amount"),
|
|
1219
|
+
]
|
|
1220
|
+
base_reward_amount: Annotated[
|
|
1221
|
+
Decimal | None,
|
|
1222
|
+
Field(default=Decimal("0"), description="Base reward credit amount"),
|
|
1223
|
+
]
|
|
1224
|
+
base_permanent_amount: Annotated[
|
|
1225
|
+
Decimal | None,
|
|
1226
|
+
Field(default=Decimal("0"), description="Base permanent credit amount"),
|
|
1227
|
+
]
|
|
971
1228
|
fee_platform_amount: Annotated[
|
|
972
|
-
|
|
1229
|
+
Decimal | None,
|
|
973
1230
|
Field(default=Decimal("0"), description="Platform fee amount"),
|
|
974
1231
|
]
|
|
975
1232
|
fee_platform_free_amount: Annotated[
|
|
976
|
-
|
|
1233
|
+
Decimal | None,
|
|
977
1234
|
Field(
|
|
978
1235
|
default=Decimal("0"), description="Platform fee amount from free credits"
|
|
979
1236
|
),
|
|
980
1237
|
]
|
|
981
1238
|
fee_platform_reward_amount: Annotated[
|
|
982
|
-
|
|
1239
|
+
Decimal | None,
|
|
983
1240
|
Field(
|
|
984
1241
|
default=Decimal("0"), description="Platform fee amount from reward credits"
|
|
985
1242
|
),
|
|
986
1243
|
]
|
|
987
1244
|
fee_platform_permanent_amount: Annotated[
|
|
988
|
-
|
|
1245
|
+
Decimal | None,
|
|
989
1246
|
Field(
|
|
990
1247
|
default=Decimal("0"),
|
|
991
1248
|
description="Platform fee amount from permanent credits",
|
|
992
1249
|
),
|
|
993
1250
|
]
|
|
994
1251
|
fee_dev_account: Annotated[
|
|
995
|
-
|
|
1252
|
+
str | None, Field(None, description="Developer account ID receiving fee")
|
|
996
1253
|
]
|
|
997
1254
|
fee_dev_amount: Annotated[
|
|
998
|
-
|
|
1255
|
+
Decimal | None,
|
|
999
1256
|
Field(default=Decimal("0"), description="Developer fee amount"),
|
|
1000
1257
|
]
|
|
1001
1258
|
fee_dev_free_amount: Annotated[
|
|
1002
|
-
|
|
1259
|
+
Decimal | None,
|
|
1003
1260
|
Field(
|
|
1004
1261
|
default=Decimal("0"), description="Developer fee amount from free credits"
|
|
1005
1262
|
),
|
|
1006
1263
|
]
|
|
1007
1264
|
fee_dev_reward_amount: Annotated[
|
|
1008
|
-
|
|
1265
|
+
Decimal | None,
|
|
1009
1266
|
Field(
|
|
1010
1267
|
default=Decimal("0"), description="Developer fee amount from reward credits"
|
|
1011
1268
|
),
|
|
1012
1269
|
]
|
|
1013
1270
|
fee_dev_permanent_amount: Annotated[
|
|
1014
|
-
|
|
1271
|
+
Decimal | None,
|
|
1015
1272
|
Field(
|
|
1016
1273
|
default=Decimal("0"),
|
|
1017
1274
|
description="Developer fee amount from permanent credits",
|
|
1018
1275
|
),
|
|
1019
1276
|
]
|
|
1020
1277
|
fee_agent_account: Annotated[
|
|
1021
|
-
|
|
1278
|
+
str | None, Field(None, description="Agent account ID receiving fee")
|
|
1022
1279
|
]
|
|
1023
1280
|
fee_agent_amount: Annotated[
|
|
1024
|
-
|
|
1281
|
+
Decimal | None, Field(default=Decimal("0"), description="Agent fee amount")
|
|
1025
1282
|
]
|
|
1026
1283
|
fee_agent_free_amount: Annotated[
|
|
1027
|
-
|
|
1284
|
+
Decimal | None,
|
|
1028
1285
|
Field(default=Decimal("0"), description="Agent fee amount from free credits"),
|
|
1029
1286
|
]
|
|
1030
1287
|
fee_agent_reward_amount: Annotated[
|
|
1031
|
-
|
|
1288
|
+
Decimal | None,
|
|
1032
1289
|
Field(default=Decimal("0"), description="Agent fee amount from reward credits"),
|
|
1033
1290
|
]
|
|
1034
1291
|
fee_agent_permanent_amount: Annotated[
|
|
1035
|
-
|
|
1292
|
+
Decimal | None,
|
|
1036
1293
|
Field(
|
|
1037
1294
|
default=Decimal("0"), description="Agent fee amount from permanent credits"
|
|
1038
1295
|
),
|
|
1039
1296
|
]
|
|
1040
1297
|
free_amount: Annotated[
|
|
1041
|
-
|
|
1298
|
+
Decimal | None,
|
|
1042
1299
|
Field(default=Decimal("0"), description="Free credit amount involved"),
|
|
1043
1300
|
]
|
|
1044
1301
|
reward_amount: Annotated[
|
|
1045
|
-
|
|
1302
|
+
Decimal | None,
|
|
1046
1303
|
Field(default=Decimal("0"), description="Reward credit amount involved"),
|
|
1047
1304
|
]
|
|
1048
1305
|
permanent_amount: Annotated[
|
|
1049
|
-
|
|
1306
|
+
Decimal | None,
|
|
1050
1307
|
Field(default=Decimal("0"), description="Permanent credit amount involved"),
|
|
1051
1308
|
]
|
|
1052
|
-
note: Annotated[
|
|
1309
|
+
note: Annotated[str | None, Field(None, description="Additional notes")]
|
|
1053
1310
|
created_at: Annotated[
|
|
1054
1311
|
datetime, Field(description="Timestamp when this event was created")
|
|
1055
1312
|
]
|
|
@@ -1062,6 +1319,9 @@ class CreditEvent(BaseModel):
|
|
|
1062
1319
|
"base_original_amount",
|
|
1063
1320
|
"base_llm_amount",
|
|
1064
1321
|
"base_skill_amount",
|
|
1322
|
+
"base_free_amount",
|
|
1323
|
+
"base_reward_amount",
|
|
1324
|
+
"base_permanent_amount",
|
|
1065
1325
|
"fee_platform_amount",
|
|
1066
1326
|
"fee_platform_free_amount",
|
|
1067
1327
|
"fee_platform_reward_amount",
|
|
@@ -1079,13 +1339,13 @@ class CreditEvent(BaseModel):
|
|
|
1079
1339
|
"permanent_amount",
|
|
1080
1340
|
)
|
|
1081
1341
|
@classmethod
|
|
1082
|
-
def round_decimal(cls, v: Any) ->
|
|
1342
|
+
def round_decimal(cls, v: Any) -> Decimal | None:
|
|
1083
1343
|
"""Round decimal values to 4 decimal places."""
|
|
1084
1344
|
if v is None:
|
|
1085
1345
|
return None
|
|
1086
1346
|
if isinstance(v, Decimal):
|
|
1087
1347
|
return v.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1088
|
-
elif isinstance(v,
|
|
1348
|
+
elif isinstance(v, int | float):
|
|
1089
1349
|
return Decimal(str(v)).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1090
1350
|
return v
|
|
1091
1351
|
|
|
@@ -1133,6 +1393,7 @@ class TransactionType(str, Enum):
|
|
|
1133
1393
|
REFUND = "refund"
|
|
1134
1394
|
ADJUSTMENT = "adjustment"
|
|
1135
1395
|
REFILL = "refill"
|
|
1396
|
+
WITHDRAW = "withdraw"
|
|
1136
1397
|
# Sync with RewardType values
|
|
1137
1398
|
REWARD = "reward"
|
|
1138
1399
|
EVENT_REWARD = "event_reward"
|
|
@@ -1183,6 +1444,21 @@ class CreditTransactionTable(Base):
|
|
|
1183
1444
|
default=0,
|
|
1184
1445
|
nullable=False,
|
|
1185
1446
|
)
|
|
1447
|
+
free_amount = Column(
|
|
1448
|
+
Numeric(22, 4),
|
|
1449
|
+
default=0,
|
|
1450
|
+
nullable=False,
|
|
1451
|
+
)
|
|
1452
|
+
reward_amount = Column(
|
|
1453
|
+
Numeric(22, 4),
|
|
1454
|
+
default=0,
|
|
1455
|
+
nullable=False,
|
|
1456
|
+
)
|
|
1457
|
+
permanent_amount = Column(
|
|
1458
|
+
Numeric(22, 4),
|
|
1459
|
+
default=0,
|
|
1460
|
+
nullable=False,
|
|
1461
|
+
)
|
|
1186
1462
|
credit_type = Column(
|
|
1187
1463
|
String,
|
|
1188
1464
|
nullable=False,
|
|
@@ -1223,14 +1499,28 @@ class CreditTransaction(BaseModel):
|
|
|
1223
1499
|
change_amount: Annotated[
|
|
1224
1500
|
Decimal, Field(default=Decimal("0"), description="Amount of credits changed")
|
|
1225
1501
|
]
|
|
1502
|
+
free_amount: Annotated[
|
|
1503
|
+
Decimal,
|
|
1504
|
+
Field(default=Decimal("0"), description="Amount of free credits changed"),
|
|
1505
|
+
]
|
|
1506
|
+
reward_amount: Annotated[
|
|
1507
|
+
Decimal,
|
|
1508
|
+
Field(default=Decimal("0"), description="Amount of reward credits changed"),
|
|
1509
|
+
]
|
|
1510
|
+
permanent_amount: Annotated[
|
|
1511
|
+
Decimal,
|
|
1512
|
+
Field(default=Decimal("0"), description="Amount of permanent credits changed"),
|
|
1513
|
+
]
|
|
1226
1514
|
|
|
1227
|
-
@field_validator(
|
|
1515
|
+
@field_validator(
|
|
1516
|
+
"change_amount", "free_amount", "reward_amount", "permanent_amount"
|
|
1517
|
+
)
|
|
1228
1518
|
@classmethod
|
|
1229
1519
|
def round_decimal(cls, v: Any) -> Decimal:
|
|
1230
1520
|
"""Round decimal values to 4 decimal places."""
|
|
1231
1521
|
if isinstance(v, Decimal):
|
|
1232
1522
|
return v.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1233
|
-
elif isinstance(v,
|
|
1523
|
+
elif isinstance(v, int | float):
|
|
1234
1524
|
return Decimal(str(v)).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1235
1525
|
return v
|
|
1236
1526
|
|
|
@@ -1295,7 +1585,7 @@ class CreditPriceTable(Base):
|
|
|
1295
1585
|
DateTime(timezone=True),
|
|
1296
1586
|
nullable=False,
|
|
1297
1587
|
server_default=func.now(),
|
|
1298
|
-
onupdate=lambda: datetime.now(
|
|
1588
|
+
onupdate=lambda: datetime.now(UTC),
|
|
1299
1589
|
)
|
|
1300
1590
|
|
|
1301
1591
|
|
|
@@ -1333,7 +1623,7 @@ class CreditPrice(BaseModel):
|
|
|
1333
1623
|
"""Round decimal values to 4 decimal places."""
|
|
1334
1624
|
if isinstance(v, Decimal):
|
|
1335
1625
|
return v.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1336
|
-
elif isinstance(v,
|
|
1626
|
+
elif isinstance(v, int | float):
|
|
1337
1627
|
return Decimal(str(v)).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1338
1628
|
return v
|
|
1339
1629
|
|
|
@@ -1410,13 +1700,11 @@ class CreditPriceLog(BaseModel):
|
|
|
1410
1700
|
"""Round decimal values to 4 decimal places."""
|
|
1411
1701
|
if isinstance(v, Decimal):
|
|
1412
1702
|
return v.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1413
|
-
elif isinstance(v,
|
|
1703
|
+
elif isinstance(v, int | float):
|
|
1414
1704
|
return Decimal(str(v)).quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)
|
|
1415
1705
|
return v
|
|
1416
1706
|
|
|
1417
|
-
note: Annotated[
|
|
1418
|
-
Optional[str], Field(None, description="Note about the modification")
|
|
1419
|
-
]
|
|
1707
|
+
note: Annotated[str | None, Field(None, description="Note about the modification")]
|
|
1420
1708
|
modified_by: Annotated[
|
|
1421
1709
|
str, Field(description="ID of the user who made the modification")
|
|
1422
1710
|
]
|