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/llm.py
ADDED
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Annotated, Any, Optional
|
|
7
|
+
|
|
8
|
+
from intentkit.models.app_setting import AppSetting
|
|
9
|
+
from intentkit.models.base import Base
|
|
10
|
+
from intentkit.models.db import get_session
|
|
11
|
+
from intentkit.models.redis import get_redis
|
|
12
|
+
from intentkit.utils.error import IntentKitLookUpError
|
|
13
|
+
from langchain_core.language_models import LanguageModelLike
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
15
|
+
from sqlalchemy import Boolean, Column, DateTime, Integer, Numeric, String, func, select
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
_credit_per_usdc = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LLMProvider(str, Enum):
|
|
23
|
+
OPENAI = "openai"
|
|
24
|
+
DEEPSEEK = "deepseek"
|
|
25
|
+
XAI = "xai"
|
|
26
|
+
ETERNAL = "eternal"
|
|
27
|
+
REIGENT = "reigent"
|
|
28
|
+
VENICE = "venice"
|
|
29
|
+
|
|
30
|
+
def display_name(self) -> str:
|
|
31
|
+
"""Return user-friendly display name for the provider."""
|
|
32
|
+
display_names = {
|
|
33
|
+
self.OPENAI: "OpenAI",
|
|
34
|
+
self.DEEPSEEK: "DeepSeek",
|
|
35
|
+
self.XAI: "xAI",
|
|
36
|
+
self.ETERNAL: "Others",
|
|
37
|
+
self.REIGENT: "Others",
|
|
38
|
+
self.VENICE: "Others",
|
|
39
|
+
}
|
|
40
|
+
return display_names.get(self, self.value)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class LLMModelInfoTable(Base):
|
|
44
|
+
"""Database table model for LLM model information."""
|
|
45
|
+
|
|
46
|
+
__tablename__ = "llm_models"
|
|
47
|
+
|
|
48
|
+
id = Column(String, primary_key=True)
|
|
49
|
+
name = Column(String, nullable=False)
|
|
50
|
+
provider = Column(String, nullable=False) # Stored as string enum value
|
|
51
|
+
enabled = Column(Boolean, nullable=False, default=True)
|
|
52
|
+
input_price = Column(
|
|
53
|
+
Numeric(22, 4), nullable=False
|
|
54
|
+
) # Price per 1M input tokens in USD
|
|
55
|
+
output_price = Column(
|
|
56
|
+
Numeric(22, 4), nullable=False
|
|
57
|
+
) # Price per 1M output tokens in USD
|
|
58
|
+
price_level = Column(Integer, nullable=True) # Price level rating from 1-5
|
|
59
|
+
context_length = Column(Integer, nullable=False) # Maximum context length in tokens
|
|
60
|
+
output_length = Column(Integer, nullable=False) # Maximum output length in tokens
|
|
61
|
+
intelligence = Column(Integer, nullable=False) # Intelligence rating from 1-5
|
|
62
|
+
speed = Column(Integer, nullable=False) # Speed rating from 1-5
|
|
63
|
+
supports_image_input = Column(Boolean, nullable=False, default=False)
|
|
64
|
+
supports_skill_calls = Column(Boolean, nullable=False, default=False)
|
|
65
|
+
supports_structured_output = Column(Boolean, nullable=False, default=False)
|
|
66
|
+
has_reasoning = Column(Boolean, nullable=False, default=False)
|
|
67
|
+
supports_search = Column(Boolean, nullable=False, default=False)
|
|
68
|
+
supports_temperature = Column(Boolean, nullable=False, default=True)
|
|
69
|
+
supports_frequency_penalty = Column(Boolean, nullable=False, default=True)
|
|
70
|
+
supports_presence_penalty = Column(Boolean, nullable=False, default=True)
|
|
71
|
+
api_base = Column(String, nullable=True) # Custom API base URL
|
|
72
|
+
timeout = Column(Integer, nullable=False, default=180) # Default timeout in seconds
|
|
73
|
+
created_at = Column(
|
|
74
|
+
DateTime(timezone=True),
|
|
75
|
+
nullable=False,
|
|
76
|
+
server_default=func.now(),
|
|
77
|
+
)
|
|
78
|
+
updated_at = Column(
|
|
79
|
+
DateTime(timezone=True),
|
|
80
|
+
nullable=False,
|
|
81
|
+
server_default=func.now(),
|
|
82
|
+
onupdate=lambda: datetime.now(timezone.utc),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class LLMModelInfo(BaseModel):
|
|
87
|
+
"""Information about an LLM model."""
|
|
88
|
+
|
|
89
|
+
model_config = ConfigDict(
|
|
90
|
+
from_attributes=True,
|
|
91
|
+
use_enum_values=True,
|
|
92
|
+
json_encoders={datetime: lambda v: v.isoformat(timespec="milliseconds")},
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
id: str
|
|
96
|
+
name: str
|
|
97
|
+
provider: LLMProvider
|
|
98
|
+
enabled: bool = Field(default=True)
|
|
99
|
+
input_price: Decimal # Price per 1M input tokens in USD
|
|
100
|
+
output_price: Decimal # Price per 1M output tokens in USD
|
|
101
|
+
price_level: Optional[int] = Field(
|
|
102
|
+
default=None, ge=1, le=5
|
|
103
|
+
) # Price level rating from 1-5
|
|
104
|
+
context_length: int # Maximum context length in tokens
|
|
105
|
+
output_length: int # Maximum output length in tokens
|
|
106
|
+
intelligence: int = Field(ge=1, le=5) # Intelligence rating from 1-5
|
|
107
|
+
speed: int = Field(ge=1, le=5) # Speed rating from 1-5
|
|
108
|
+
supports_image_input: bool = False # Whether the model supports image inputs
|
|
109
|
+
supports_skill_calls: bool = False # Whether the model supports skill/tool calls
|
|
110
|
+
supports_structured_output: bool = (
|
|
111
|
+
False # Whether the model supports structured output
|
|
112
|
+
)
|
|
113
|
+
has_reasoning: bool = False # Whether the model has strong reasoning capabilities
|
|
114
|
+
supports_search: bool = (
|
|
115
|
+
False # Whether the model supports native search functionality
|
|
116
|
+
)
|
|
117
|
+
supports_temperature: bool = (
|
|
118
|
+
True # Whether the model supports temperature parameter
|
|
119
|
+
)
|
|
120
|
+
supports_frequency_penalty: bool = (
|
|
121
|
+
True # Whether the model supports frequency_penalty parameter
|
|
122
|
+
)
|
|
123
|
+
supports_presence_penalty: bool = (
|
|
124
|
+
True # Whether the model supports presence_penalty parameter
|
|
125
|
+
)
|
|
126
|
+
api_base: Optional[str] = (
|
|
127
|
+
None # Custom API base URL if not using provider's default
|
|
128
|
+
)
|
|
129
|
+
timeout: int = 180 # Default timeout in seconds
|
|
130
|
+
created_at: Annotated[
|
|
131
|
+
datetime,
|
|
132
|
+
Field(
|
|
133
|
+
description="Timestamp when this data was created",
|
|
134
|
+
default=datetime.now(timezone.utc),
|
|
135
|
+
),
|
|
136
|
+
]
|
|
137
|
+
updated_at: Annotated[
|
|
138
|
+
datetime,
|
|
139
|
+
Field(
|
|
140
|
+
description="Timestamp when this data was updated",
|
|
141
|
+
default=datetime.now(timezone.utc),
|
|
142
|
+
),
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
async def get(model_id: str) -> "LLMModelInfo":
|
|
147
|
+
"""Get a model by ID with Redis caching.
|
|
148
|
+
|
|
149
|
+
The model info is cached in Redis for 3 minutes.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
model_id: ID of the model to retrieve
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
LLMModelInfo: The model info if found, None otherwise
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
has_redis = True
|
|
159
|
+
# Redis cache key for model info
|
|
160
|
+
cache_key = f"intentkit:llm_model:{model_id}"
|
|
161
|
+
cache_ttl = 180 # 3 minutes in seconds
|
|
162
|
+
|
|
163
|
+
# Try to get from Redis cache first
|
|
164
|
+
redis = get_redis()
|
|
165
|
+
cached_data = await redis.get(cache_key)
|
|
166
|
+
|
|
167
|
+
if cached_data:
|
|
168
|
+
# If found in cache, deserialize and return
|
|
169
|
+
try:
|
|
170
|
+
return LLMModelInfo.model_validate_json(cached_data)
|
|
171
|
+
except (json.JSONDecodeError, TypeError):
|
|
172
|
+
# If cache is corrupted, invalidate it
|
|
173
|
+
await redis.delete(cache_key)
|
|
174
|
+
except Exception:
|
|
175
|
+
has_redis = False
|
|
176
|
+
logger.debug("No redis when get model info")
|
|
177
|
+
|
|
178
|
+
# If not in cache or cache is invalid, get from database
|
|
179
|
+
async with get_session() as session:
|
|
180
|
+
# Query the database for the model
|
|
181
|
+
stmt = select(LLMModelInfoTable).where(LLMModelInfoTable.id == model_id)
|
|
182
|
+
model = await session.scalar(stmt)
|
|
183
|
+
|
|
184
|
+
# If model exists in database, convert to LLMModelInfo model and cache it
|
|
185
|
+
if model:
|
|
186
|
+
# Convert provider string to enum
|
|
187
|
+
model_info = LLMModelInfo.model_validate(model)
|
|
188
|
+
|
|
189
|
+
# Cache the model in Redis
|
|
190
|
+
if has_redis:
|
|
191
|
+
await redis.set(
|
|
192
|
+
cache_key,
|
|
193
|
+
model_info.model_dump_json(),
|
|
194
|
+
ex=cache_ttl,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
return model_info
|
|
198
|
+
|
|
199
|
+
# If not found in database, check AVAILABLE_MODELS
|
|
200
|
+
if model_id in AVAILABLE_MODELS:
|
|
201
|
+
model_info = AVAILABLE_MODELS[model_id]
|
|
202
|
+
|
|
203
|
+
# Cache the model in Redis
|
|
204
|
+
if has_redis:
|
|
205
|
+
await redis.set(cache_key, model_info.model_dump_json(), ex=cache_ttl)
|
|
206
|
+
|
|
207
|
+
return model_info
|
|
208
|
+
|
|
209
|
+
# Not found anywhere
|
|
210
|
+
raise IntentKitLookUpError(f"Model {model_id} not found")
|
|
211
|
+
|
|
212
|
+
async def calculate_cost(self, input_tokens: int, output_tokens: int) -> Decimal:
|
|
213
|
+
global _credit_per_usdc
|
|
214
|
+
if not _credit_per_usdc:
|
|
215
|
+
_credit_per_usdc = (await AppSetting.payment()).credit_per_usdc
|
|
216
|
+
"""Calculate the cost for a given number of tokens."""
|
|
217
|
+
input_cost = (
|
|
218
|
+
_credit_per_usdc
|
|
219
|
+
* Decimal(input_tokens)
|
|
220
|
+
* self.input_price
|
|
221
|
+
/ Decimal(1000000)
|
|
222
|
+
)
|
|
223
|
+
output_cost = (
|
|
224
|
+
_credit_per_usdc
|
|
225
|
+
* Decimal(output_tokens)
|
|
226
|
+
* self.output_price
|
|
227
|
+
/ Decimal(1000000)
|
|
228
|
+
)
|
|
229
|
+
return input_cost + output_cost
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# Define all available models
|
|
233
|
+
AVAILABLE_MODELS = {
|
|
234
|
+
# OpenAI models
|
|
235
|
+
"gpt-4o": LLMModelInfo(
|
|
236
|
+
id="gpt-4o",
|
|
237
|
+
name="GPT-4o",
|
|
238
|
+
provider=LLMProvider.OPENAI,
|
|
239
|
+
input_price=Decimal("2.50"), # per 1M input tokens
|
|
240
|
+
output_price=Decimal("10.00"), # per 1M output tokens
|
|
241
|
+
context_length=128000,
|
|
242
|
+
output_length=4096,
|
|
243
|
+
intelligence=4,
|
|
244
|
+
speed=3,
|
|
245
|
+
supports_image_input=True,
|
|
246
|
+
supports_skill_calls=True,
|
|
247
|
+
supports_structured_output=True,
|
|
248
|
+
supports_search=True,
|
|
249
|
+
supports_frequency_penalty=False,
|
|
250
|
+
supports_presence_penalty=False,
|
|
251
|
+
),
|
|
252
|
+
"gpt-4o-mini": LLMModelInfo(
|
|
253
|
+
id="gpt-4o-mini",
|
|
254
|
+
name="GPT-4o Mini",
|
|
255
|
+
provider=LLMProvider.OPENAI,
|
|
256
|
+
input_price=Decimal("0.15"), # per 1M input tokens
|
|
257
|
+
output_price=Decimal("0.60"), # per 1M output tokens
|
|
258
|
+
context_length=128000,
|
|
259
|
+
output_length=4096,
|
|
260
|
+
intelligence=3,
|
|
261
|
+
speed=4,
|
|
262
|
+
supports_image_input=False,
|
|
263
|
+
supports_skill_calls=True,
|
|
264
|
+
supports_structured_output=True,
|
|
265
|
+
supports_search=True,
|
|
266
|
+
supports_frequency_penalty=False,
|
|
267
|
+
supports_presence_penalty=False,
|
|
268
|
+
),
|
|
269
|
+
"gpt-4.1-nano": LLMModelInfo(
|
|
270
|
+
id="gpt-4.1-nano",
|
|
271
|
+
name="GPT-4.1 Nano",
|
|
272
|
+
provider=LLMProvider.OPENAI,
|
|
273
|
+
input_price=Decimal("0.1"), # per 1M input tokens
|
|
274
|
+
output_price=Decimal("0.4"), # per 1M output tokens
|
|
275
|
+
context_length=128000,
|
|
276
|
+
output_length=4096,
|
|
277
|
+
intelligence=3,
|
|
278
|
+
speed=5,
|
|
279
|
+
supports_image_input=False,
|
|
280
|
+
supports_skill_calls=True,
|
|
281
|
+
supports_structured_output=True,
|
|
282
|
+
supports_frequency_penalty=False,
|
|
283
|
+
supports_presence_penalty=False,
|
|
284
|
+
),
|
|
285
|
+
"gpt-4.1-mini": LLMModelInfo(
|
|
286
|
+
id="gpt-4.1-mini",
|
|
287
|
+
name="GPT-4.1 Mini",
|
|
288
|
+
provider=LLMProvider.OPENAI,
|
|
289
|
+
input_price=Decimal("0.4"), # per 1M input tokens
|
|
290
|
+
output_price=Decimal("1.6"), # per 1M output tokens
|
|
291
|
+
context_length=128000,
|
|
292
|
+
output_length=4096,
|
|
293
|
+
intelligence=4,
|
|
294
|
+
speed=4,
|
|
295
|
+
supports_image_input=False,
|
|
296
|
+
supports_skill_calls=True,
|
|
297
|
+
supports_structured_output=True,
|
|
298
|
+
supports_search=True,
|
|
299
|
+
supports_frequency_penalty=False,
|
|
300
|
+
supports_presence_penalty=False,
|
|
301
|
+
),
|
|
302
|
+
"gpt-4.1": LLMModelInfo(
|
|
303
|
+
id="gpt-4.1",
|
|
304
|
+
name="GPT-4.1",
|
|
305
|
+
provider=LLMProvider.OPENAI,
|
|
306
|
+
input_price=Decimal("2.00"), # per 1M input tokens
|
|
307
|
+
output_price=Decimal("8.00"), # per 1M output tokens
|
|
308
|
+
context_length=128000,
|
|
309
|
+
output_length=4096,
|
|
310
|
+
intelligence=5,
|
|
311
|
+
speed=3,
|
|
312
|
+
supports_image_input=True,
|
|
313
|
+
supports_skill_calls=True,
|
|
314
|
+
supports_structured_output=True,
|
|
315
|
+
supports_search=True,
|
|
316
|
+
supports_frequency_penalty=False,
|
|
317
|
+
supports_presence_penalty=False,
|
|
318
|
+
),
|
|
319
|
+
"o4-mini": LLMModelInfo(
|
|
320
|
+
id="o4-mini",
|
|
321
|
+
name="OpenAI o4-mini",
|
|
322
|
+
provider=LLMProvider.OPENAI,
|
|
323
|
+
input_price=Decimal("1.10"), # per 1M input tokens
|
|
324
|
+
output_price=Decimal("4.40"), # per 1M output tokens
|
|
325
|
+
context_length=128000,
|
|
326
|
+
output_length=4096,
|
|
327
|
+
intelligence=4,
|
|
328
|
+
speed=3,
|
|
329
|
+
supports_image_input=False,
|
|
330
|
+
supports_skill_calls=True,
|
|
331
|
+
supports_structured_output=True,
|
|
332
|
+
has_reasoning=True, # Has strong reasoning capabilities
|
|
333
|
+
supports_temperature=False,
|
|
334
|
+
supports_frequency_penalty=False,
|
|
335
|
+
supports_presence_penalty=False,
|
|
336
|
+
),
|
|
337
|
+
# Deepseek models
|
|
338
|
+
"deepseek-chat": LLMModelInfo(
|
|
339
|
+
id="deepseek-chat",
|
|
340
|
+
name="Deepseek V3 (0324)",
|
|
341
|
+
provider=LLMProvider.DEEPSEEK,
|
|
342
|
+
input_price=Decimal("0.27"),
|
|
343
|
+
output_price=Decimal("1.10"),
|
|
344
|
+
context_length=60000,
|
|
345
|
+
output_length=4096,
|
|
346
|
+
intelligence=4,
|
|
347
|
+
speed=3,
|
|
348
|
+
supports_image_input=False,
|
|
349
|
+
supports_skill_calls=True,
|
|
350
|
+
supports_structured_output=True,
|
|
351
|
+
api_base="https://api.deepseek.com",
|
|
352
|
+
timeout=300,
|
|
353
|
+
),
|
|
354
|
+
"deepseek-reasoner": LLMModelInfo(
|
|
355
|
+
id="deepseek-reasoner",
|
|
356
|
+
name="Deepseek R1",
|
|
357
|
+
provider=LLMProvider.DEEPSEEK,
|
|
358
|
+
input_price=Decimal("0.55"),
|
|
359
|
+
output_price=Decimal("2.19"),
|
|
360
|
+
context_length=60000,
|
|
361
|
+
output_length=4096,
|
|
362
|
+
intelligence=4,
|
|
363
|
+
speed=2,
|
|
364
|
+
supports_image_input=False,
|
|
365
|
+
supports_skill_calls=True,
|
|
366
|
+
supports_structured_output=True,
|
|
367
|
+
has_reasoning=True, # Has strong reasoning capabilities
|
|
368
|
+
api_base="https://api.deepseek.com",
|
|
369
|
+
timeout=300,
|
|
370
|
+
),
|
|
371
|
+
# XAI models
|
|
372
|
+
"grok-2": LLMModelInfo(
|
|
373
|
+
id="grok-2",
|
|
374
|
+
name="Grok 2",
|
|
375
|
+
provider=LLMProvider.XAI,
|
|
376
|
+
input_price=Decimal("2"),
|
|
377
|
+
output_price=Decimal("10"),
|
|
378
|
+
context_length=120000,
|
|
379
|
+
output_length=4096,
|
|
380
|
+
intelligence=3,
|
|
381
|
+
speed=3,
|
|
382
|
+
supports_image_input=False,
|
|
383
|
+
supports_skill_calls=True,
|
|
384
|
+
supports_structured_output=True,
|
|
385
|
+
timeout=180,
|
|
386
|
+
),
|
|
387
|
+
"grok-3": LLMModelInfo(
|
|
388
|
+
id="grok-3",
|
|
389
|
+
name="Grok 3",
|
|
390
|
+
provider=LLMProvider.XAI,
|
|
391
|
+
input_price=Decimal("3"),
|
|
392
|
+
output_price=Decimal("15"),
|
|
393
|
+
context_length=131072,
|
|
394
|
+
output_length=4096,
|
|
395
|
+
intelligence=5,
|
|
396
|
+
speed=3,
|
|
397
|
+
supports_image_input=False,
|
|
398
|
+
supports_skill_calls=True,
|
|
399
|
+
supports_structured_output=True,
|
|
400
|
+
supports_search=True,
|
|
401
|
+
timeout=180,
|
|
402
|
+
),
|
|
403
|
+
"grok-3-mini": LLMModelInfo(
|
|
404
|
+
id="grok-3-mini",
|
|
405
|
+
name="Grok 3 Mini",
|
|
406
|
+
provider=LLMProvider.XAI,
|
|
407
|
+
input_price=Decimal("0.3"),
|
|
408
|
+
output_price=Decimal("0.5"),
|
|
409
|
+
context_length=131072,
|
|
410
|
+
output_length=4096,
|
|
411
|
+
intelligence=5,
|
|
412
|
+
speed=3,
|
|
413
|
+
supports_image_input=False,
|
|
414
|
+
supports_skill_calls=True,
|
|
415
|
+
supports_structured_output=True,
|
|
416
|
+
has_reasoning=True, # Has strong reasoning capabilities
|
|
417
|
+
supports_frequency_penalty=False,
|
|
418
|
+
supports_presence_penalty=False, # Grok-3-mini doesn't support presence_penalty
|
|
419
|
+
timeout=180,
|
|
420
|
+
),
|
|
421
|
+
# Eternal AI models
|
|
422
|
+
"eternalai": LLMModelInfo(
|
|
423
|
+
id="eternalai",
|
|
424
|
+
name="Eternal AI (Llama-3.3-70B)",
|
|
425
|
+
provider=LLMProvider.ETERNAL,
|
|
426
|
+
input_price=Decimal("0.25"),
|
|
427
|
+
output_price=Decimal("0.75"),
|
|
428
|
+
context_length=60000,
|
|
429
|
+
output_length=4096,
|
|
430
|
+
intelligence=4,
|
|
431
|
+
speed=3,
|
|
432
|
+
supports_image_input=False,
|
|
433
|
+
supports_skill_calls=True,
|
|
434
|
+
supports_structured_output=True,
|
|
435
|
+
api_base="https://api.eternalai.org/v1",
|
|
436
|
+
timeout=300,
|
|
437
|
+
),
|
|
438
|
+
# Reigent models
|
|
439
|
+
"reigent": LLMModelInfo(
|
|
440
|
+
id="reigent",
|
|
441
|
+
name="REI Network",
|
|
442
|
+
provider=LLMProvider.REIGENT,
|
|
443
|
+
input_price=Decimal("0.50"), # Placeholder price, update with actual pricing
|
|
444
|
+
output_price=Decimal("1.50"), # Placeholder price, update with actual pricing
|
|
445
|
+
context_length=32000,
|
|
446
|
+
output_length=4096,
|
|
447
|
+
intelligence=4,
|
|
448
|
+
speed=3,
|
|
449
|
+
supports_image_input=False,
|
|
450
|
+
supports_skill_calls=True,
|
|
451
|
+
supports_structured_output=True,
|
|
452
|
+
supports_temperature=False,
|
|
453
|
+
supports_frequency_penalty=False,
|
|
454
|
+
supports_presence_penalty=False,
|
|
455
|
+
api_base="https://api.reisearch.box/v1",
|
|
456
|
+
timeout=300,
|
|
457
|
+
),
|
|
458
|
+
# Venice models
|
|
459
|
+
"venice-uncensored": LLMModelInfo(
|
|
460
|
+
id="venice-uncensored",
|
|
461
|
+
name="Venice Uncensored",
|
|
462
|
+
provider=LLMProvider.VENICE,
|
|
463
|
+
input_price=Decimal("0.50"), # Placeholder price, update with actual pricing
|
|
464
|
+
output_price=Decimal("2.00"), # Placeholder price, update with actual pricing
|
|
465
|
+
context_length=32000,
|
|
466
|
+
output_length=4096,
|
|
467
|
+
intelligence=3,
|
|
468
|
+
speed=3,
|
|
469
|
+
supports_image_input=False,
|
|
470
|
+
supports_skill_calls=True,
|
|
471
|
+
supports_structured_output=True,
|
|
472
|
+
supports_temperature=True,
|
|
473
|
+
supports_frequency_penalty=False,
|
|
474
|
+
supports_presence_penalty=False,
|
|
475
|
+
api_base="https://api.venice.ai/api/v1",
|
|
476
|
+
timeout=300,
|
|
477
|
+
),
|
|
478
|
+
"venice-llama-4-maverick-17b": LLMModelInfo(
|
|
479
|
+
id="venice-llama-4-maverick-17b",
|
|
480
|
+
name="Venice Llama-4 Maverick 17B",
|
|
481
|
+
provider=LLMProvider.VENICE,
|
|
482
|
+
input_price=Decimal("1.50"),
|
|
483
|
+
output_price=Decimal("6.00"),
|
|
484
|
+
context_length=32000,
|
|
485
|
+
output_length=4096,
|
|
486
|
+
intelligence=3,
|
|
487
|
+
speed=3,
|
|
488
|
+
supports_image_input=False,
|
|
489
|
+
supports_skill_calls=True,
|
|
490
|
+
supports_structured_output=True,
|
|
491
|
+
supports_temperature=True,
|
|
492
|
+
supports_frequency_penalty=False,
|
|
493
|
+
supports_presence_penalty=False,
|
|
494
|
+
api_base="https://api.venice.ai/api/v1",
|
|
495
|
+
timeout=300,
|
|
496
|
+
),
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
class LLMModel(BaseModel):
|
|
501
|
+
"""Base model for LLM configuration."""
|
|
502
|
+
|
|
503
|
+
model_name: str
|
|
504
|
+
temperature: float = 0.7
|
|
505
|
+
frequency_penalty: float = 0.0
|
|
506
|
+
presence_penalty: float = 0.0
|
|
507
|
+
info: LLMModelInfo
|
|
508
|
+
|
|
509
|
+
async def model_info(self) -> LLMModelInfo:
|
|
510
|
+
"""Get the model information with caching.
|
|
511
|
+
|
|
512
|
+
First tries to get from cache, then database, then AVAILABLE_MODELS.
|
|
513
|
+
Raises ValueError if model is not found anywhere.
|
|
514
|
+
"""
|
|
515
|
+
model_info = await LLMModelInfo.get(self.model_name)
|
|
516
|
+
return model_info
|
|
517
|
+
|
|
518
|
+
# This will be implemented by subclasses to return the appropriate LLM instance
|
|
519
|
+
async def create_instance(self, config: Any) -> LanguageModelLike:
|
|
520
|
+
"""Create and return the LLM instance based on the configuration."""
|
|
521
|
+
raise NotImplementedError("Subclasses must implement create_instance")
|
|
522
|
+
|
|
523
|
+
async def get_token_limit(self) -> int:
|
|
524
|
+
"""Get the token limit for this model."""
|
|
525
|
+
info = await self.model_info()
|
|
526
|
+
return info.context_length
|
|
527
|
+
|
|
528
|
+
async def calculate_cost(self, input_tokens: int, output_tokens: int) -> Decimal:
|
|
529
|
+
"""Calculate the cost for a given number of tokens."""
|
|
530
|
+
info = await self.model_info()
|
|
531
|
+
return await info.calculate_cost(input_tokens, output_tokens)
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
class OpenAILLM(LLMModel):
|
|
535
|
+
"""OpenAI LLM configuration."""
|
|
536
|
+
|
|
537
|
+
async def create_instance(self, config: Any) -> LanguageModelLike:
|
|
538
|
+
"""Create and return a ChatOpenAI instance."""
|
|
539
|
+
from langchain_openai import ChatOpenAI
|
|
540
|
+
|
|
541
|
+
info = await self.model_info()
|
|
542
|
+
|
|
543
|
+
kwargs = {
|
|
544
|
+
"model_name": self.model_name,
|
|
545
|
+
"openai_api_key": config.openai_api_key,
|
|
546
|
+
"timeout": info.timeout,
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
# Add optional parameters based on model support
|
|
550
|
+
if info.supports_temperature:
|
|
551
|
+
kwargs["temperature"] = self.temperature
|
|
552
|
+
|
|
553
|
+
if info.supports_frequency_penalty:
|
|
554
|
+
kwargs["frequency_penalty"] = self.frequency_penalty
|
|
555
|
+
|
|
556
|
+
if info.supports_presence_penalty:
|
|
557
|
+
kwargs["presence_penalty"] = self.presence_penalty
|
|
558
|
+
|
|
559
|
+
if info.api_base:
|
|
560
|
+
kwargs["openai_api_base"] = info.api_base
|
|
561
|
+
|
|
562
|
+
logger.debug(f"Creating ChatOpenAI instance with kwargs: {kwargs}")
|
|
563
|
+
|
|
564
|
+
return ChatOpenAI(**kwargs)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
class DeepseekLLM(LLMModel):
|
|
568
|
+
"""Deepseek LLM configuration."""
|
|
569
|
+
|
|
570
|
+
async def create_instance(self, config: Any) -> LanguageModelLike:
|
|
571
|
+
"""Create and return a ChatDeepseek instance."""
|
|
572
|
+
|
|
573
|
+
from langchain_openai import ChatOpenAI
|
|
574
|
+
|
|
575
|
+
info = await self.model_info()
|
|
576
|
+
|
|
577
|
+
kwargs = {
|
|
578
|
+
"model_name": self.model_name,
|
|
579
|
+
"openai_api_key": config.deepseek_api_key,
|
|
580
|
+
"timeout": info.timeout,
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
# Add optional parameters based on model support
|
|
584
|
+
if info.supports_temperature:
|
|
585
|
+
kwargs["temperature"] = self.temperature
|
|
586
|
+
|
|
587
|
+
if info.supports_frequency_penalty:
|
|
588
|
+
kwargs["frequency_penalty"] = self.frequency_penalty
|
|
589
|
+
|
|
590
|
+
if info.supports_presence_penalty:
|
|
591
|
+
kwargs["presence_penalty"] = self.presence_penalty
|
|
592
|
+
|
|
593
|
+
if info.api_base:
|
|
594
|
+
kwargs["openai_api_base"] = info.api_base
|
|
595
|
+
|
|
596
|
+
return ChatOpenAI(**kwargs)
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
class XAILLM(LLMModel):
|
|
600
|
+
"""XAI (Grok) LLM configuration."""
|
|
601
|
+
|
|
602
|
+
async def create_instance(self, config: Any) -> LanguageModelLike:
|
|
603
|
+
"""Create and return a ChatXAI instance."""
|
|
604
|
+
|
|
605
|
+
from langchain_xai import ChatXAI
|
|
606
|
+
|
|
607
|
+
info = await self.model_info()
|
|
608
|
+
|
|
609
|
+
kwargs = {
|
|
610
|
+
"model_name": self.model_name,
|
|
611
|
+
"xai_api_key": config.xai_api_key,
|
|
612
|
+
"timeout": info.timeout,
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
# Add optional parameters based on model support
|
|
616
|
+
if info.supports_temperature:
|
|
617
|
+
kwargs["temperature"] = self.temperature
|
|
618
|
+
|
|
619
|
+
if info.supports_frequency_penalty:
|
|
620
|
+
kwargs["frequency_penalty"] = self.frequency_penalty
|
|
621
|
+
|
|
622
|
+
if info.supports_presence_penalty:
|
|
623
|
+
kwargs["presence_penalty"] = self.presence_penalty
|
|
624
|
+
|
|
625
|
+
if self.model_name in ["grok-3", "grok-3-mini"]:
|
|
626
|
+
kwargs["search_parameters"] = {"mode": "auto"}
|
|
627
|
+
|
|
628
|
+
return ChatXAI(**kwargs)
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
class EternalLLM(LLMModel):
|
|
632
|
+
"""Eternal AI LLM configuration."""
|
|
633
|
+
|
|
634
|
+
async def create_instance(self, config: Any) -> LanguageModelLike:
|
|
635
|
+
"""Create and return a ChatOpenAI instance configured for Eternal AI."""
|
|
636
|
+
from langchain_openai import ChatOpenAI
|
|
637
|
+
|
|
638
|
+
info = await self.model_info()
|
|
639
|
+
|
|
640
|
+
# Override model name for Eternal AI
|
|
641
|
+
actual_model = "unsloth/Llama-3.3-70B-Instruct-bnb-4bit"
|
|
642
|
+
|
|
643
|
+
kwargs = {
|
|
644
|
+
"model_name": actual_model,
|
|
645
|
+
"openai_api_key": config.eternal_api_key,
|
|
646
|
+
"openai_api_base": info.api_base,
|
|
647
|
+
"timeout": info.timeout,
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
# Add optional parameters based on model support
|
|
651
|
+
if info.supports_temperature:
|
|
652
|
+
kwargs["temperature"] = self.temperature
|
|
653
|
+
|
|
654
|
+
if info.supports_frequency_penalty:
|
|
655
|
+
kwargs["frequency_penalty"] = self.frequency_penalty
|
|
656
|
+
|
|
657
|
+
if info.supports_presence_penalty:
|
|
658
|
+
kwargs["presence_penalty"] = self.presence_penalty
|
|
659
|
+
|
|
660
|
+
return ChatOpenAI(**kwargs)
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
class ReigentLLM(LLMModel):
|
|
664
|
+
"""Reigent LLM configuration."""
|
|
665
|
+
|
|
666
|
+
async def create_instance(self, config: Any) -> LanguageModelLike:
|
|
667
|
+
"""Create and return a ChatOpenAI instance configured for Reigent."""
|
|
668
|
+
from langchain_openai import ChatOpenAI
|
|
669
|
+
|
|
670
|
+
info = await self.model_info()
|
|
671
|
+
|
|
672
|
+
kwargs = {
|
|
673
|
+
"openai_api_key": config.reigent_api_key,
|
|
674
|
+
"openai_api_base": info.api_base,
|
|
675
|
+
"timeout": info.timeout,
|
|
676
|
+
"model_kwargs": {
|
|
677
|
+
# Override any specific parameters required for Reigent API
|
|
678
|
+
# The Reigent API requires 'tools' instead of 'functions' and might have some specific formatting requirements
|
|
679
|
+
},
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return ChatOpenAI(**kwargs)
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
class VeniceLLM(LLMModel):
|
|
686
|
+
"""Venice LLM configuration."""
|
|
687
|
+
|
|
688
|
+
async def create_instance(self, config: Any) -> LanguageModelLike:
|
|
689
|
+
"""Create and return a ChatOpenAI instance configured for Venice."""
|
|
690
|
+
from langchain_openai import ChatOpenAI
|
|
691
|
+
|
|
692
|
+
info = await self.model_info()
|
|
693
|
+
|
|
694
|
+
kwargs = {
|
|
695
|
+
"openai_api_key": config.venice_api_key,
|
|
696
|
+
"openai_api_base": info.api_base,
|
|
697
|
+
"timeout": info.timeout,
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
return ChatOpenAI(**kwargs)
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
# Factory function to create the appropriate LLM model based on the model name
|
|
704
|
+
async def create_llm_model(
|
|
705
|
+
model_name: str,
|
|
706
|
+
temperature: float = 0.7,
|
|
707
|
+
frequency_penalty: float = 0.0,
|
|
708
|
+
presence_penalty: float = 0.0,
|
|
709
|
+
) -> LLMModel:
|
|
710
|
+
"""
|
|
711
|
+
Create an LLM model instance based on the model name.
|
|
712
|
+
|
|
713
|
+
Args:
|
|
714
|
+
model_name: The name of the model to use
|
|
715
|
+
temperature: The temperature parameter for the model
|
|
716
|
+
frequency_penalty: The frequency penalty parameter for the model
|
|
717
|
+
presence_penalty: The presence penalty parameter for the model
|
|
718
|
+
|
|
719
|
+
Returns:
|
|
720
|
+
An instance of a subclass of LLMModel
|
|
721
|
+
"""
|
|
722
|
+
info = await LLMModelInfo.get(model_name)
|
|
723
|
+
|
|
724
|
+
base_params = {
|
|
725
|
+
"model_name": model_name,
|
|
726
|
+
"temperature": temperature,
|
|
727
|
+
"frequency_penalty": frequency_penalty,
|
|
728
|
+
"presence_penalty": presence_penalty,
|
|
729
|
+
"info": info,
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
provider = info.provider
|
|
733
|
+
|
|
734
|
+
if provider == LLMProvider.DEEPSEEK:
|
|
735
|
+
return DeepseekLLM(**base_params)
|
|
736
|
+
elif provider == LLMProvider.XAI:
|
|
737
|
+
return XAILLM(**base_params)
|
|
738
|
+
elif provider == LLMProvider.ETERNAL:
|
|
739
|
+
return EternalLLM(**base_params)
|
|
740
|
+
elif provider == LLMProvider.REIGENT:
|
|
741
|
+
return ReigentLLM(**base_params)
|
|
742
|
+
elif provider == LLMProvider.VENICE:
|
|
743
|
+
return VeniceLLM(**base_params)
|
|
744
|
+
else:
|
|
745
|
+
# Default to OpenAI
|
|
746
|
+
return OpenAILLM(**base_params)
|