mirror of
https://github.com/mistralai/mistral-vibe
synced 2026-04-25 17:14:55 +02:00
Co-authored-by: Clément Drouin <clement.drouin@mistral.ai> Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai> Co-authored-by: Gauthier Guinet <43207538+Gguinet@users.noreply.github.com> Co-authored-by: Kim-Adeline Miguel <kimadeline.miguel@mistral.ai> Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com> Co-authored-by: Quentin <torroba.q@gmail.com> Co-authored-by: Simon <80467011+sorgfresser@users.noreply.github.com> Co-authored-by: Simon Van de Kerckhove <simon.vandekerckhove@mistral.ai> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: angelapopopo <angele.lenglemetz@mistral.ai> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
122 lines
3.7 KiB
Python
122 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
from enum import StrEnum
|
|
import logging
|
|
from os import getenv
|
|
|
|
from vibe.cli.plan_offer.ports.whoami_gateway import (
|
|
WhoAmIGateway,
|
|
WhoAmIGatewayError,
|
|
WhoAmIGatewayUnauthorized,
|
|
WhoAmIPlanType,
|
|
WhoAmIResponse,
|
|
)
|
|
from vibe.core.config import DEFAULT_MISTRAL_API_ENV_KEY, ProviderConfig
|
|
from vibe.core.types import Backend
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CONSOLE_CLI_URL = "https://console.mistral.ai/codestral/cli"
|
|
UPGRADE_URL = CONSOLE_CLI_URL
|
|
SWITCH_TO_PRO_KEY_URL = CONSOLE_CLI_URL
|
|
|
|
|
|
class MistralCodePlanName(StrEnum):
|
|
FREE = "F"
|
|
ENTERPRISE = "E"
|
|
|
|
|
|
class PlanInfo:
|
|
plan_type: WhoAmIPlanType
|
|
plan_name: str
|
|
prompt_switching_to_pro_plan: bool
|
|
|
|
def __init__(
|
|
self,
|
|
plan_type: WhoAmIPlanType,
|
|
plan_name: str = "",
|
|
prompt_switching_to_pro_plan: bool = False,
|
|
) -> None:
|
|
self.plan_type = plan_type
|
|
self.plan_name = plan_name
|
|
self.prompt_switching_to_pro_plan = prompt_switching_to_pro_plan
|
|
|
|
@classmethod
|
|
def from_response(cls, response: WhoAmIResponse) -> PlanInfo:
|
|
return cls(
|
|
plan_type=response.plan_type,
|
|
plan_name=response.plan_name,
|
|
prompt_switching_to_pro_plan=response.prompt_switching_to_pro_plan,
|
|
)
|
|
|
|
def is_paid_api_plan(self) -> bool:
|
|
return self.plan_type == WhoAmIPlanType.API and not self.is_free_api_plan()
|
|
|
|
def is_free_api_plan(self) -> bool:
|
|
return self.plan_type == WhoAmIPlanType.API and "FREE" in self.plan_name.upper()
|
|
|
|
def is_chat_pro_plan(self) -> bool:
|
|
return self.plan_type == WhoAmIPlanType.CHAT
|
|
|
|
def is_free_mistral_code_plan(self) -> bool:
|
|
return (
|
|
self.plan_type == WhoAmIPlanType.MISTRAL_CODE
|
|
and self.plan_name.upper() == MistralCodePlanName.FREE
|
|
)
|
|
|
|
def is_mistral_code_enterprise_plan(self) -> bool:
|
|
return (
|
|
self.plan_type == WhoAmIPlanType.MISTRAL_CODE
|
|
and self.plan_name.upper() == MistralCodePlanName.ENTERPRISE
|
|
)
|
|
|
|
|
|
async def decide_plan_offer(api_key: str | None, gateway: WhoAmIGateway) -> PlanInfo:
|
|
if not api_key:
|
|
return PlanInfo(WhoAmIPlanType.UNKNOWN)
|
|
try:
|
|
response = await gateway.whoami(api_key)
|
|
return PlanInfo.from_response(response)
|
|
except WhoAmIGatewayUnauthorized:
|
|
return PlanInfo(WhoAmIPlanType.UNAUTHORIZED)
|
|
except WhoAmIGatewayError:
|
|
logger.warning("Failed to fetch plan status.", exc_info=True)
|
|
return PlanInfo(WhoAmIPlanType.UNKNOWN)
|
|
|
|
|
|
def resolve_api_key_for_plan(provider: ProviderConfig) -> str | None:
|
|
api_env_key = DEFAULT_MISTRAL_API_ENV_KEY
|
|
|
|
if provider.backend == Backend.MISTRAL:
|
|
api_env_key = provider.api_key_env_var
|
|
|
|
return getenv(api_env_key)
|
|
|
|
|
|
def plan_offer_cta(payload: PlanInfo | None) -> str | None:
|
|
if not payload:
|
|
return
|
|
if payload.prompt_switching_to_pro_plan:
|
|
return f"### Switch to your [Le Chat Pro API key]({SWITCH_TO_PRO_KEY_URL})"
|
|
if (
|
|
payload.plan_type in {WhoAmIPlanType.API, WhoAmIPlanType.UNAUTHORIZED}
|
|
or payload.is_free_mistral_code_plan()
|
|
):
|
|
return f"### Unlock more with Vibe - [Upgrade to Le Chat Pro]({UPGRADE_URL})"
|
|
|
|
|
|
def plan_title(payload: PlanInfo | None) -> str | None: # noqa: PLR0911
|
|
if not payload:
|
|
return None
|
|
if payload.is_chat_pro_plan():
|
|
return "[Subscription] Pro"
|
|
if payload.is_free_api_plan():
|
|
return "[API] Experiment plan"
|
|
if payload.is_paid_api_plan():
|
|
return "[API] Scale plan"
|
|
if payload.is_free_mistral_code_plan():
|
|
return "Mistral Code Free"
|
|
if payload.is_mistral_code_enterprise_plan():
|
|
return "Mistral Code Enterprise"
|
|
return None
|