Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai>
Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com>
Co-authored-by: Peter Evers <peter.evers@mistral.ai>
Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai>
Co-authored-by: Quentin <quentin.torroba@mistral.ai>
Co-authored-by: Val <102326092+vdeva@users.noreply.github.com>
Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Clément Drouin 2026-05-29 16:17:54 +02:00 committed by GitHub
parent 198277af3f
commit ad0d5c9520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 969 additions and 461 deletions

View file

@ -12,8 +12,8 @@ from vibe.cli.plan_offer.ports.whoami_gateway import (
WhoAmIResponse,
)
from vibe.core.config import (
DEFAULT_CONSOLE_BASE_URL,
DEFAULT_MISTRAL_API_ENV_KEY,
DEFAULT_VIBE_BASE_URL,
ProviderConfig,
)
from vibe.core.types import Backend
@ -97,20 +97,18 @@ def resolve_api_key_for_plan(provider: ProviderConfig) -> str | None:
def plan_offer_cta(
payload: PlanInfo | None, console_base_url: str = DEFAULT_CONSOLE_BASE_URL
payload: PlanInfo | None, *, vibe_base_url: str = DEFAULT_VIBE_BASE_URL
) -> str | None:
if not payload:
return
console_cli_url = f"{console_base_url.rstrip('/')}/codestral/cli"
switch_to_pro_key_url = console_cli_url
upgrade_url = console_cli_url
vibe_api_key_url = f"{vibe_base_url.rstrip('/')}/code/extensions?focus=key"
if payload.prompt_switching_to_pro_plan:
return f"### Switch to your [Le Chat Pro API key]({switch_to_pro_key_url})"
return f"### Switch to your [Vibe Pro API key]({vibe_api_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})"
return f"### Unlock more with Vibe - [Upgrade to Vibe Pro]({vibe_api_key_url})"
def plan_title(payload: PlanInfo | None) -> str | None: # noqa: PLR0911

View file

@ -2183,32 +2183,26 @@ class VibeApp(App): # noqa: PLR0904
if not self.event_handler:
return
old_tokens = self.agent_loop.stats.context_tokens
old_session_id = self.agent_loop.session_id
compact_msg = CompactMessage()
self.event_handler.current_compact = compact_msg
await self._mount_and_scroll(compact_msg)
self._agent_task = asyncio.create_task(
self._run_compact(compact_msg, old_tokens, old_session_id, cmd_args.strip())
self._run_compact(compact_msg, old_session_id, cmd_args.strip())
)
async def _run_compact(
self,
compact_msg: CompactMessage,
old_tokens: int,
old_session_id: str,
extra_instructions: str = "",
) -> None:
self._agent_running = True
try:
await self.agent_loop.compact(extra_instructions=extra_instructions)
new_tokens = self.agent_loop.stats.context_tokens
compact_msg.set_complete(
old_tokens=old_tokens,
new_tokens=new_tokens,
old_session_id=old_session_id,
new_session_id=self.agent_loop.session_id,
old_session_id=old_session_id, new_session_id=self.agent_loop.session_id
)
except asyncio.CancelledError:
@ -2887,13 +2881,18 @@ class VibeApp(App): # noqa: PLR0904
if self._chat_input_container:
self._chat_input_container.switching_mode = True
loop = asyncio.get_running_loop()
def schedule_switch() -> None:
self._switch_agent_generation += 1
my_gen = self._switch_agent_generation
def switch_agent_sync() -> None:
try:
asyncio.run(self.agent_loop.switch_agent(new_profile.name))
future = asyncio.run_coroutine_threadsafe(
self.agent_loop.switch_agent(new_profile.name), loop
)
future.result()
self.agent_loop.set_approval_callback(self._approval_callback)
self.agent_loop.set_user_input_callback(self._user_input_callback)
finally:
@ -3031,7 +3030,7 @@ class VibeApp(App): # noqa: PLR0904
if content is not None:
body = content
plan_offer = plan_offer_cta(
self._plan_info, console_base_url=self.config.console_base_url
self._plan_info, vibe_base_url=self.config.vibe_base_url
)
if plan_offer is not None:
body = f"{body}\n\n{plan_offer}"
@ -3059,12 +3058,10 @@ class VibeApp(App): # noqa: PLR0904
if not self._show_vscode_extension_promo:
return
promo_message = VscodeExtensionPromoMessage()
if self._history_widget_indices:
promo_message.add_class("after-history")
messages_area = self._cached_messages_area or self.query_one("#messages")
chat = self._cached_chat or self.query_one("#chat", ChatScroll)
should_anchor = chat.is_at_bottom
await chat.mount(promo_message, after=messages_area)
await chat.mount(promo_message, before=messages_area)
if should_anchor:
chat.anchor()
self.run_worker(self._record_vscode_extension_promo_shown(), exclusive=False)

View file

@ -1281,10 +1281,6 @@ NarratorStatus {
link-color-hover: $mistral_orange;
}
.vscode-extension-promo-message.after-history {
margin-top: 1;
}
#sessionpicker-app {
width: 100%;
height: auto;

View file

@ -229,10 +229,7 @@ class EventHandler:
async def _handle_compact_end(self, event: CompactEndEvent) -> None:
if self.current_compact:
self.current_compact.set_complete(
old_tokens=event.old_context_tokens,
new_tokens=event.new_context_tokens,
old_session_id=event.old_session_id,
new_session_id=event.new_session_id,
old_session_id=event.old_session_id, new_session_id=event.new_session_id
)
self.current_compact = None

View file

@ -3,7 +3,7 @@ from __future__ import annotations
from textual.message import Message
from vibe.cli.textual_ui.widgets.status_message import StatusMessage
from vibe.core.utils import compact_reduction_display
from vibe.core.utils import compact_complete_display
class CompactMessage(StatusMessage):
@ -15,8 +15,6 @@ class CompactMessage(StatusMessage):
def __init__(self) -> None:
super().__init__()
self.add_class("compact-message")
self.old_tokens: int | None = None
self.new_tokens: int | None = None
self.old_session_id: str | None = None
self.new_session_id: str | None = None
self.error_message: str | None = None
@ -28,23 +26,13 @@ class CompactMessage(StatusMessage):
if self.error_message:
return f"Error: {self.error_message}"
return compact_reduction_display(
self.old_tokens,
self.new_tokens,
old_session_id=self.old_session_id,
new_session_id=self.new_session_id,
return compact_complete_display(
old_session_id=self.old_session_id, new_session_id=self.new_session_id
)
def set_complete(
self,
old_tokens: int | None = None,
new_tokens: int | None = None,
*,
old_session_id: str | None = None,
new_session_id: str | None = None,
self, *, old_session_id: str | None = None, new_session_id: str | None = None
) -> None:
self.old_tokens = old_tokens
self.new_tokens = new_tokens
self.old_session_id = old_session_id
self.new_session_id = new_session_id
self.stop_spinning(success=True)