v2.17.1 (#823)
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:
parent
6bedf271ce
commit
725d3a56ce
35 changed files with 1330 additions and 288 deletions
|
|
@ -165,6 +165,25 @@ class TestHandleHelp:
|
|||
for cmd in main_commands:
|
||||
assert f"/{cmd}" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_lists_registered_commands_alphabetically(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
await _prompt(acp_agent_loop, session_id, "/help")
|
||||
|
||||
content = _get_message_texts(acp_agent_loop)[0]
|
||||
commands_section = content.split("### Available Commands\n\n", maxsplit=1)[
|
||||
1
|
||||
].split("\n\n", maxsplit=1)[0]
|
||||
command_names = [
|
||||
line.split("`", maxsplit=2)[1].removeprefix("/")
|
||||
for line in commands_section.splitlines()
|
||||
if line.startswith("- ")
|
||||
]
|
||||
|
||||
assert command_names == sorted(command_names)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_includes_user_invocable_skills(
|
||||
self, acp_agent_loop_with_skills: VibeAcpAgentLoop, skills_dir: Path
|
||||
|
|
@ -267,6 +286,28 @@ class TestHandleTeleport:
|
|||
]
|
||||
assert _get_tool_updates(acp_agent_loop) == []
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_teleport_replies_with_error_when_model_not_mistral(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
|
||||
with patch(
|
||||
"vibe.core.config._settings.VibeConfig.is_active_model_mistral",
|
||||
return_value=False,
|
||||
):
|
||||
response = await _prompt(acp_agent_loop, session_id, "/teleport")
|
||||
|
||||
assert response.stop_reason == "end_turn"
|
||||
assert response.field_meta == {
|
||||
"tool_name": "teleport",
|
||||
"teleport": {"status": "unavailable"},
|
||||
}
|
||||
texts = _get_message_texts(acp_agent_loop)
|
||||
assert len(texts) == 1
|
||||
assert "active Mistral model" in texts[0]
|
||||
assert _get_tool_updates(acp_agent_loop) == []
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_teleport_sends_tool_updates_and_structured_url(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
|
|
@ -542,6 +583,25 @@ class TestCommandFallthrough:
|
|||
|
||||
|
||||
class TestAvailableCommandsWithSkills:
|
||||
@pytest.mark.asyncio
|
||||
async def test_available_commands_are_alphabetical(
|
||||
self, acp_agent_loop_with_skills: VibeAcpAgentLoop, skills_dir: Path
|
||||
) -> None:
|
||||
create_skill(skills_dir, "alpha-skill", "First skill")
|
||||
|
||||
await acp_agent_loop_with_skills.new_session(
|
||||
cwd=str(Path.cwd()), mcp_servers=[]
|
||||
)
|
||||
await _wait_for_available_commands(acp_agent_loop_with_skills)
|
||||
|
||||
updates = _get_client(acp_agent_loop_with_skills)._session_updates
|
||||
available = [
|
||||
u for u in updates if isinstance(u.update, AvailableCommandsUpdate)
|
||||
]
|
||||
cmd_names = [c.name for c in available[0].update.available_commands]
|
||||
|
||||
assert cmd_names == sorted(cmd_names)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_skills_appear_in_available_commands(
|
||||
self, acp_agent_loop_with_skills: VibeAcpAgentLoop, skills_dir: Path
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class TestACPInitialize:
|
|||
),
|
||||
)
|
||||
assert response.agent_info == Implementation(
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.17.0"
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.17.1"
|
||||
)
|
||||
|
||||
assert response.auth_methods is not None
|
||||
|
|
@ -172,7 +172,7 @@ class TestACPInitialize:
|
|||
),
|
||||
)
|
||||
assert response.agent_info == Implementation(
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.17.0"
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.17.1"
|
||||
)
|
||||
|
||||
assert response.auth_methods is not None
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class TestLoadSession:
|
|||
"cwd": str(tmp_working_directory.resolve()),
|
||||
"repoRoot": None,
|
||||
"ignoredFiles": ["AGENTS.md"],
|
||||
"availableDecisions": ["trust_cwd", "trust_session", "decline"],
|
||||
"availableDecisions": ["trust_cwd", "decline"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ class TestACPNewSession:
|
|||
"cwd": str(tmp_working_directory.resolve()),
|
||||
"repoRoot": None,
|
||||
"ignoredFiles": ["AGENTS.md"],
|
||||
"availableDecisions": ["trust_cwd", "trust_session", "decline"],
|
||||
"availableDecisions": ["trust_cwd", "decline"],
|
||||
},
|
||||
}
|
||||
assert trusted_folders_manager.is_trusted(tmp_working_directory) is None
|
||||
|
|
@ -230,12 +230,7 @@ class TestACPNewSession:
|
|||
"cwd": str(cwd.resolve()),
|
||||
"repoRoot": str(repo.resolve()),
|
||||
"ignoredFiles": ["AGENTS.md"],
|
||||
"availableDecisions": [
|
||||
"trust_repo",
|
||||
"trust_cwd",
|
||||
"trust_session",
|
||||
"decline",
|
||||
],
|
||||
"availableDecisions": ["trust_repo", "trust_cwd", "decline"],
|
||||
},
|
||||
}
|
||||
assert trusted_folders_manager.is_trusted(repo) is None
|
||||
|
|
@ -264,7 +259,7 @@ class TestACPNewSession:
|
|||
"cwd": str(tmp_working_directory.resolve()),
|
||||
"repoRoot": None,
|
||||
"ignoredFiles": ["AGENTS.md"],
|
||||
"availableDecisions": ["trust_cwd", "trust_session", "decline"],
|
||||
"availableDecisions": ["trust_cwd", "decline"],
|
||||
},
|
||||
}
|
||||
assert trusted_folders_manager.is_trusted(tmp_working_directory) is False
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
|
@ -20,6 +21,14 @@ async def _system_prompt(acp_agent_loop: VibeAcpAgentLoop, session_id: str) -> s
|
|||
return session.agent_loop.messages[0].content or ""
|
||||
|
||||
|
||||
async def _wait_for_background_tasks(
|
||||
acp_agent_loop: VibeAcpAgentLoop, session_id: str
|
||||
) -> None:
|
||||
session = acp_agent_loop.sessions[session_id]
|
||||
while session._tasks:
|
||||
await asyncio.gather(*list(session._tasks))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def acp_agent_loop(
|
||||
backend: FakeBackend, monkeypatch: pytest.MonkeyPatch
|
||||
|
|
@ -66,12 +75,12 @@ class TestWorkspaceTrustExtMethods:
|
|||
"cwd": str(tmp_working_directory.resolve()),
|
||||
"repoRoot": None,
|
||||
"ignoredFiles": ["AGENTS.md"],
|
||||
"availableDecisions": ["trust_cwd", "trust_session", "decline"],
|
||||
"availableDecisions": ["trust_cwd", "decline"],
|
||||
},
|
||||
}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workspace_trust_decision_trusts_session_and_reloads_session(
|
||||
async def test_workspace_trust_decision_trusts_cwd_and_reloads_session(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop, tmp_working_directory: Path
|
||||
) -> None:
|
||||
(tmp_working_directory / "AGENTS.md").write_text(
|
||||
|
|
@ -90,19 +99,74 @@ class TestWorkspaceTrustExtMethods:
|
|||
"trust/decision",
|
||||
{
|
||||
"cwd": str(tmp_working_directory),
|
||||
"decision": "trust_session",
|
||||
"decision": "trust_cwd",
|
||||
"session_id": session_response.session_id,
|
||||
},
|
||||
)
|
||||
|
||||
assert response == {"trust_status": "session", "details": None}
|
||||
assert response == {"trust_status": "trusted", "details": None}
|
||||
normalized = str(tmp_working_directory.resolve())
|
||||
assert normalized in trusted_folders_manager._session_trusted
|
||||
assert normalized not in trusted_folders_manager._trusted
|
||||
assert normalized not in trusted_folders_manager._session_trusted
|
||||
assert normalized in trusted_folders_manager._trusted
|
||||
await _wait_for_background_tasks(acp_agent_loop, session_response.session_id)
|
||||
assert "Reloaded session instructions" in await _system_prompt(
|
||||
acp_agent_loop, session_response.session_id
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workspace_trust_decision_returns_before_reload_completes(
|
||||
self,
|
||||
acp_agent_loop: VibeAcpAgentLoop,
|
||||
tmp_working_directory: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
(tmp_working_directory / "AGENTS.md").write_text(
|
||||
"Slow reload instructions", encoding="utf-8"
|
||||
)
|
||||
|
||||
session_response = await acp_agent_loop.new_session(
|
||||
cwd=str(tmp_working_directory), mcp_servers=[]
|
||||
)
|
||||
assert session_response.session_id is not None
|
||||
|
||||
reload_started = asyncio.Event()
|
||||
release_reload = asyncio.Event()
|
||||
|
||||
async def slow_reload_session_config(session) -> None:
|
||||
reload_started.set()
|
||||
await release_reload.wait()
|
||||
|
||||
monkeypatch.setattr(
|
||||
acp_agent_loop, "_reload_session_config", slow_reload_session_config
|
||||
)
|
||||
|
||||
decision_task = asyncio.create_task(
|
||||
acp_agent_loop.ext_method(
|
||||
"trust/decision",
|
||||
{
|
||||
"cwd": str(tmp_working_directory),
|
||||
"decision": "trust_cwd",
|
||||
"session_id": session_response.session_id,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
await asyncio.wait_for(reload_started.wait(), timeout=1)
|
||||
await asyncio.sleep(0)
|
||||
|
||||
assert decision_task.done()
|
||||
assert decision_task.result() == {
|
||||
"trust_status": "trusted",
|
||||
"details": None,
|
||||
}
|
||||
finally:
|
||||
release_reload.set()
|
||||
await decision_task
|
||||
await _wait_for_background_tasks(
|
||||
acp_agent_loop, session_response.session_id
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workspace_trust_decision_rejects_unavailable_decision(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop, tmp_working_directory: Path
|
||||
|
|
@ -117,6 +181,12 @@ class TestWorkspaceTrustExtMethods:
|
|||
{"cwd": str(tmp_working_directory), "decision": "trust_repo"},
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidRequestError):
|
||||
await acp_agent_loop.ext_method(
|
||||
"trust/decision",
|
||||
{"cwd": str(tmp_working_directory), "decision": "trust_session"},
|
||||
)
|
||||
|
||||
assert trusted_folders_manager.is_trusted(tmp_working_directory) is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -132,7 +202,7 @@ class TestWorkspaceTrustExtMethods:
|
|||
"trust/decision",
|
||||
{
|
||||
"cwd": str(tmp_working_directory),
|
||||
"decision": "trust_session",
|
||||
"decision": "trust_cwd",
|
||||
"session_id": "missing-session",
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue