vibe/tests/acp/test_agent_thought.py
Mathias Gesbert 51fecc67d9
2.1.0 (#317)
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: Nicolas Karolak <nicolas@karolak.fr>
2026-02-11 18:17:30 +01:00

154 lines
5.4 KiB
Python

from __future__ import annotations
from pathlib import Path
from unittest.mock import patch
from acp.schema import AgentThoughtChunk, TextContentBlock
import pytest
from tests.acp.conftest import _create_acp_agent
from tests.conftest import build_test_vibe_config
from tests.stubs.fake_backend import FakeBackend
from tests.stubs.fake_client import FakeClient
from vibe.acp.acp_agent_loop import VibeAcpAgentLoop
from vibe.core.agent_loop import AgentLoop
from vibe.core.types import LLMChunk, LLMMessage, LLMUsage, Role
def _create_backend_with_reasoning(
reasoning_content: str, content: str = "Hi"
) -> FakeBackend:
return FakeBackend(
LLMChunk(
message=LLMMessage(
role=Role.assistant,
content=content,
reasoning_content=reasoning_content,
),
usage=LLMUsage(prompt_tokens=1, completion_tokens=1),
)
)
@pytest.fixture
def backend_with_reasoning() -> FakeBackend:
return _create_backend_with_reasoning("Let me think about this...")
@pytest.fixture
def acp_agent_loop_with_reasoning(
backend_with_reasoning: FakeBackend,
) -> VibeAcpAgentLoop:
config = build_test_vibe_config(active_model="devstral-latest")
class PatchedAgentLoop(AgentLoop):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **{**kwargs, "backend": backend_with_reasoning})
self._base_config = config
self.agent_manager.invalidate_config()
patch("vibe.acp.acp_agent_loop.AgentLoop", side_effect=PatchedAgentLoop).start()
return _create_acp_agent()
class TestACPAgentThought:
@pytest.mark.asyncio
async def test_prompt_with_reasoning_emits_agent_thought_chunk(
self, acp_agent_loop_with_reasoning: VibeAcpAgentLoop
) -> None:
session_response = await acp_agent_loop_with_reasoning.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
session_id = session_response.session_id
await acp_agent_loop_with_reasoning.prompt(
session_id=session_id,
prompt=[TextContentBlock(type="text", text="Just say hi")],
)
fake_client: FakeClient = acp_agent_loop_with_reasoning.client # type: ignore
thought_updates = [
update
for update in fake_client._session_updates
if isinstance(update.update, AgentThoughtChunk)
]
assert len(thought_updates) == 1
thought_chunk = thought_updates[0].update
assert thought_chunk.session_update == "agent_thought_chunk"
assert thought_chunk.content is not None
assert isinstance(thought_chunk.content, TextContentBlock)
assert thought_chunk.content.text == "Let me think about this..."
@pytest.mark.asyncio
async def test_prompt_without_reasoning_does_not_emit_agent_thought_chunk(
self, acp_agent_loop: VibeAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
session_id = session_response.session_id
await acp_agent_loop.prompt(
session_id=session_id,
prompt=[TextContentBlock(type="text", text="Just say hi")],
)
fake_client: FakeClient = acp_agent_loop.client # type: ignore
thought_updates = [
update
for update in fake_client._session_updates
if isinstance(update.update, AgentThoughtChunk)
]
assert len(thought_updates) == 0
@pytest.mark.asyncio
async def test_agent_thought_chunk_contains_text_content_block(
self, acp_agent_loop_with_reasoning: VibeAcpAgentLoop
) -> None:
session_response = await acp_agent_loop_with_reasoning.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
session_id = session_response.session_id
await acp_agent_loop_with_reasoning.prompt(
session_id=session_id, prompt=[TextContentBlock(type="text", text="Hello")]
)
fake_client: FakeClient = acp_agent_loop_with_reasoning.client # type: ignore
thought_updates = [
update
for update in fake_client._session_updates
if isinstance(update.update, AgentThoughtChunk)
]
assert len(thought_updates) == 1
thought_chunk = thought_updates[0].update
assert thought_chunk.content.type == "text"
@pytest.mark.asyncio
async def test_agent_thought_chunk_contains_message_id(
self, acp_agent_loop_with_reasoning: VibeAcpAgentLoop
) -> None:
session_response = await acp_agent_loop_with_reasoning.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
session_id = session_response.session_id
await acp_agent_loop_with_reasoning.prompt(
session_id=session_id, prompt=[TextContentBlock(type="text", text="Hello")]
)
fake_client: FakeClient = acp_agent_loop_with_reasoning.client # type: ignore
thought_updates = [
update
for update in fake_client._session_updates
if isinstance(update.update, AgentThoughtChunk)
]
assert len(thought_updates) == 1
thought_chunk = thought_updates[0].update
assert thought_chunk.field_meta is not None
assert "messageId" in thought_chunk.field_meta
assert thought_chunk.field_meta["messageId"] is not None