Co-authored-by: Jean Burellier <sheplu@users.noreply.github.com>
Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com>
Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai>
Co-authored-by: Nelson PROIA <144663685+Nelson-PROIA@users.noreply.github.com>
Co-authored-by: renovate-mistral[bot] <253709520+renovate-mistral[bot]@users.noreply.github.com>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Clément Drouin 2026-06-19 17:39:44 +02:00 committed by GitHub
parent 6bedf271ce
commit 725d3a56ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 1330 additions and 288 deletions

View file

@ -11,6 +11,7 @@ from tests.conftest import build_test_vibe_app, build_test_vibe_config
from tests.constants import OPENAI_BASE_URL
from vibe.cli.plan_offer.ports.whoami_gateway import WhoAmIPlanType, WhoAmIResponse
from vibe.cli.textual_ui.widgets.chat_input import ChatInputContainer
from vibe.cli.textual_ui.widgets.messages import ErrorMessage
from vibe.core.config import ModelConfig, ProviderConfig, VibeConfig
from vibe.core.types import Backend
@ -48,6 +49,10 @@ def _teleport_failed_events(
]
def _error_messages(app) -> list[str]:
return [error._error for error in app.query(ErrorMessage)]
@pytest.mark.asyncio
async def test_teleport_command_visible_for_paid_chat_users() -> None:
app = build_test_vibe_app(
@ -102,66 +107,101 @@ async def test_teleport_command_without_history_sends_early_failure_telemetry(
@pytest.mark.asyncio
async def test_teleport_command_hidden_when_current_key_is_not_eligible() -> None:
async def test_teleport_command_visible_but_errors_when_key_not_eligible(
telemetry_events: list[dict[str, Any]],
) -> None:
app = build_test_vibe_app(
config=_vibe_code_enabled_config(),
plan_offer_gateway=_chat_plan_gateway(prompt_switching_to_pro_plan=True),
)
async with app.run_test() as pilot:
await pilot.pause(0.2)
await _wait_until(
pilot.pause,
lambda: app.commands.get_command_name("/teleport") == "teleport",
)
assert app.commands.get_command_name("/teleport") is None
assert "/teleport" not in app.commands.get_help_text()
assert "/teleport" in app.commands.get_help_text()
input_widget = app.query_one(ChatInputContainer).input_widget
assert input_widget is not None
assert "&" not in input_widget.mode_characters
assert "&" in input_widget.mode_characters
await app.on_chat_input_container_submitted(
ChatInputContainer.Submitted("/teleport")
)
await _wait_until(
pilot.pause,
lambda: any("Vibe Pro API key" in error for error in _error_messages(app)),
)
assert _teleport_failed_events(telemetry_events) == [
{
"event_name": "vibe.teleport_failed",
"properties": {
"stage": "ineligible",
"error_class": "TeleportIneligibleError",
"push_required": False,
"nb_session_messages": 0,
"session_id": app.agent_loop.session_id,
},
}
]
@pytest.mark.asyncio
async def test_hidden_teleport_command_falls_through_as_user_text() -> None:
async def test_teleport_command_errors_instead_of_user_text_when_not_eligible() -> None:
app = build_test_vibe_app(
config=_vibe_code_enabled_config(),
plan_offer_gateway=_chat_plan_gateway(prompt_switching_to_pro_plan=True),
)
async with app.run_test() as pilot:
await pilot.pause(0.2)
await _wait_until(
pilot.pause,
lambda: app.commands.get_command_name("/teleport") == "teleport",
)
app._handle_teleport_command = AsyncMock()
app._handle_user_message = AsyncMock()
await app.on_chat_input_container_submitted(
ChatInputContainer.Submitted("/teleport")
)
await _wait_until(
pilot.pause,
lambda: any("Vibe Pro API key" in error for error in _error_messages(app)),
)
app._handle_teleport_command.assert_not_awaited()
app._handle_user_message.assert_awaited_once_with("/teleport")
app._handle_user_message.assert_not_awaited()
@pytest.mark.asyncio
async def test_hidden_ampersand_teleport_shortcut_falls_through_as_user_text() -> None:
async def test_ampersand_teleport_shortcut_errors_when_not_eligible() -> None:
app = build_test_vibe_app(
config=_vibe_code_enabled_config(),
plan_offer_gateway=_chat_plan_gateway(prompt_switching_to_pro_plan=True),
)
async with app.run_test() as pilot:
await pilot.pause(0.2)
await _wait_until(
pilot.pause,
lambda: app.commands.get_command_name("/teleport") == "teleport",
)
app._handle_teleport_command = AsyncMock()
app._handle_user_message = AsyncMock()
await app.on_chat_input_container_submitted(
ChatInputContainer.Submitted("&continue")
)
await _wait_until(
pilot.pause,
lambda: any("Vibe Pro API key" in error for error in _error_messages(app)),
)
app._handle_teleport_command.assert_not_awaited()
app._handle_user_message.assert_awaited_once_with("&continue")
app._handle_user_message.assert_not_awaited()
@pytest.mark.asyncio
async def test_teleport_command_hides_after_switching_to_non_mistral_model(
async def test_teleport_command_errors_after_switching_to_non_mistral_model(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("OPENAI_API_KEY", "mock-openai-key")
@ -223,11 +263,18 @@ async def test_teleport_command_hides_after_switching_to_non_mistral_model(
):
await app._reload_config()
await _wait_until(
pilot.pause, lambda: app.commands.get_command_name("/teleport") is None
)
assert app.commands.get_command_name("/teleport") is None
await _wait_until(pilot.pause, lambda: not app.config.is_active_model_mistral())
assert app.commands.get_command_name("/teleport") == "teleport"
input_widget = app.query_one(ChatInputContainer).input_widget
assert input_widget is not None
assert "&" not in input_widget.mode_characters
assert "&" in input_widget.mode_characters
await app.on_chat_input_container_submitted(
ChatInputContainer.Submitted("/teleport")
)
await _wait_until(
pilot.pause,
lambda: any(
"active Mistral model" in error for error in _error_messages(app)
),
)