Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai>
Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai>
Co-Authored-By: Clément Drouin <clement.drouin@mistral.ai>
Co-Authored-By: Vincent Guilloux <vincent.guilloux@mistral.ai>
Co-Authored-By: Clément Siriex <clement.sirieix@mistral.ai>
Co-Authored-By: Kim-Adeline Miguel <kimadeline.miguel@mistral.ai>
Co-Authored-By: Thaddee Tyl <thaddee.tyl@gmail.com>
Co-Authored-By: David Brochart <david.brochart@gmail.com>
Co-Authored-By: Joseph Guhlin <joseph.guhlin@gmail.com>
Co-Authored-By: Thomas Kenbeek <thomaskenbeek@gmail.com>
Co-Authored-By: Remenby31 <baptiste.cruvellier31@gmail.com>
This commit is contained in:
Mathias Gesbert 2026-01-27 16:39:30 +01:00 committed by Mathias Gesbert
parent 79f215d91c
commit d33db9fff8
217 changed files with 16911 additions and 4305 deletions

View file

@ -3,31 +3,17 @@ from __future__ import annotations
from pathlib import Path
from unittest.mock import patch
from acp import AgentSideConnection, NewSessionRequest, SetSessionModelRequest
import pytest
from tests.stubs.fake_backend import FakeBackend
from tests.stubs.fake_connection import FakeAgentSideConnection
from vibe.acp.acp_agent import VibeAcpAgent
from vibe.core.agent import Agent
from tests.acp.conftest import _create_acp_agent
from vibe.acp.acp_agent_loop import VibeAcpAgentLoop
from vibe.core.agent_loop import AgentLoop
from vibe.core.agents.models import BuiltinAgentName
from vibe.core.config import ModelConfig, VibeConfig
from vibe.core.modes import AgentMode
from vibe.core.types import LLMChunk, LLMMessage, LLMUsage, Role
@pytest.fixture
def backend() -> FakeBackend:
backend = FakeBackend(
LLMChunk(
message=LLMMessage(role=Role.assistant, content="Hi"),
usage=LLMUsage(prompt_tokens=1, completion_tokens=1),
)
)
return backend
@pytest.fixture
def acp_agent(backend: FakeBackend) -> VibeAcpAgent:
def acp_agent_loop(backend) -> VibeAcpAgentLoop:
config = VibeConfig(
active_model="devstral-latest",
models=[
@ -40,101 +26,90 @@ def acp_agent(backend: FakeBackend) -> VibeAcpAgent:
],
)
class PatchedAgent(Agent):
class PatchedAgentLoop(AgentLoop):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **{**kwargs, "backend": backend})
self.config = config
self._base_config = config
self.agent_manager.invalidate_config()
patch("vibe.acp.acp_agent.VibeAgent", side_effect=PatchedAgent).start()
patch("vibe.acp.acp_agent_loop.AgentLoop", side_effect=PatchedAgentLoop).start()
vibe_acp_agent: VibeAcpAgent | None = None
def _create_agent(connection: AgentSideConnection) -> VibeAcpAgent:
nonlocal vibe_acp_agent
vibe_acp_agent = VibeAcpAgent(connection)
return vibe_acp_agent
FakeAgentSideConnection(_create_agent)
return vibe_acp_agent # pyright: ignore[reportReturnType]
return _create_acp_agent()
class TestACPNewSession:
@pytest.mark.asyncio
async def test_new_session_response_structure(
self, acp_agent: VibeAcpAgent
self, acp_agent_loop: VibeAcpAgentLoop
) -> None:
session_response = await acp_agent.newSession(
NewSessionRequest(cwd=str(Path.cwd()), mcpServers=[])
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
assert session_response.sessionId is not None
assert session_response.session_id is not None
acp_session = next(
(
s
for s in acp_agent.sessions.values()
if s.id == session_response.sessionId
for s in acp_agent_loop.sessions.values()
if s.id == session_response.session_id
),
None,
)
assert acp_session is not None
assert (
acp_session.agent.interaction_logger.session_id
== session_response.sessionId
acp_session.agent_loop.session_logger.session_id
== session_response.session_id
)
assert session_response.sessionId == acp_session.agent.session_id
assert session_response.session_id == acp_session.agent_loop.session_id
assert session_response.models is not None
assert session_response.models.currentModelId is not None
assert session_response.models.availableModels is not None
assert len(session_response.models.availableModels) == 2
assert session_response.models.current_model_id is not None
assert session_response.models.available_models is not None
assert len(session_response.models.available_models) == 2
assert session_response.models.currentModelId == "devstral-latest"
assert session_response.models.availableModels[0].modelId == "devstral-latest"
assert session_response.models.availableModels[0].name == "devstral-latest"
assert session_response.models.availableModels[1].modelId == "devstral-small"
assert session_response.models.availableModels[1].name == "devstral-small"
assert session_response.models.current_model_id == "devstral-latest"
assert session_response.models.available_models[0].model_id == "devstral-latest"
assert session_response.models.available_models[0].name == "devstral-latest"
assert session_response.models.available_models[1].model_id == "devstral-small"
assert session_response.models.available_models[1].name == "devstral-small"
assert session_response.modes is not None
assert session_response.modes.currentModeId is not None
assert session_response.modes.availableModes is not None
assert len(session_response.modes.availableModes) == 4
assert session_response.modes.current_mode_id is not None
assert session_response.modes.available_modes is not None
assert len(session_response.modes.available_modes) == 4
assert session_response.modes.currentModeId == AgentMode.DEFAULT.value
assert session_response.modes.availableModes[0].id == AgentMode.DEFAULT.value
assert session_response.modes.availableModes[0].name == "Default"
assert (
session_response.modes.availableModes[1].id == AgentMode.AUTO_APPROVE.value
)
assert session_response.modes.availableModes[1].name == "Auto Approve"
assert session_response.modes.availableModes[2].id == AgentMode.PLAN.value
assert session_response.modes.availableModes[2].name == "Plan"
assert (
session_response.modes.availableModes[3].id == AgentMode.ACCEPT_EDITS.value
)
assert session_response.modes.availableModes[3].name == "Accept Edits"
assert session_response.modes.current_mode_id == BuiltinAgentName.DEFAULT
# Check that all primary agents are available (order may vary)
mode_ids = {m.id for m in session_response.modes.available_modes}
assert mode_ids == {
BuiltinAgentName.DEFAULT,
BuiltinAgentName.AUTO_APPROVE,
BuiltinAgentName.PLAN,
BuiltinAgentName.ACCEPT_EDITS,
}
@pytest.mark.skip(reason="TODO: Fix this test")
@pytest.mark.asyncio
async def test_new_session_preserves_model_after_set_model(
self, acp_agent: VibeAcpAgent
self, acp_agent_loop: VibeAcpAgentLoop
) -> None:
session_response = await acp_agent.newSession(
NewSessionRequest(cwd=str(Path.cwd()), mcpServers=[])
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
session_id = session_response.sessionId
session_id = session_response.session_id
assert session_response.models is not None
assert session_response.models.currentModelId == "devstral-latest"
assert session_response.models.current_model_id == "devstral-latest"
response = await acp_agent.setSessionModel(
SetSessionModelRequest(sessionId=session_id, modelId="devstral-small")
response = await acp_agent_loop.set_session_model(
session_id=session_id, model_id="devstral-small"
)
assert response is not None
session_response = await acp_agent.newSession(
NewSessionRequest(cwd=str(Path.cwd()), mcpServers=[])
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
assert session_response.models is not None
assert session_response.models.currentModelId == "devstral-small"
assert session_response.models.current_model_id == "devstral-small"