Co-authored-by: Clément Drouin <clement.drouin@mistral.ai>
Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai>
Co-authored-by: Guillaume LE GOFF <guillaume.lgf@gmail.com>
Co-authored-by: Mert Unsal <mertunsal1905@gmail.com>
Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com>
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: maximevoisin-pm <maxime.voisin@mistral.ai>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Mathias Gesbert 2026-05-27 17:10:40 +02:00 committed by GitHub
parent adb1ca74ce
commit cf3f4ca58f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
143 changed files with 3457 additions and 1351 deletions

View file

@ -19,7 +19,7 @@ from vibe.core.agents.models import (
_deep_merge,
)
from vibe.core.config import VibeConfig
from vibe.core.config.harness_files import HarnessFilesManager
from vibe.core.prompts import UtilityPrompt
from vibe.core.tools.base import ToolPermission
from vibe.core.types import LLMChunk, LLMMessage, LLMUsage, Role
@ -233,35 +233,11 @@ class TestAgentApplyToConfig:
assert "ask_user_question" in result.enabled_tools
def test_custom_prompt_found_in_global_when_missing_from_project(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
self, mock_prompts_dirs: tuple[Path, Path]
) -> None:
"""Regression test for https://github.com/mistralai/mistral-vibe/issues/288
When a custom prompt .md file is absent from the project-local prompts
directory, the system_prompt property should fall back to the global
~/.vibe/prompts/ directory and load the file from there.
"""
project_prompts = tmp_path / "project" / ".vibe" / "prompts"
project_prompts.mkdir(parents=True)
global_prompts = tmp_path / "home" / ".vibe" / "prompts"
global_prompts.mkdir(parents=True)
_, global_prompts = mock_prompts_dirs
(global_prompts / "cc.md").write_text("Global custom prompt")
class _MockManager(HarnessFilesManager):
@property
def project_prompts_dirs(self) -> list[Path]:
return [project_prompts]
@property
def user_prompts_dirs(self) -> list[Path]:
return [global_prompts]
mock_manager = _MockManager(sources=("user",))
monkeypatch.setattr(
"vibe.core.prompts.get_harness_files_manager", lambda: mock_manager
)
base = VibeConfig(include_project_context=False, include_prompt_detail=False)
agent = AgentProfile(
name="cc",
@ -275,7 +251,7 @@ class TestAgentApplyToConfig:
assert result.system_prompt == "Global custom prompt"
def test_custom_prompt_overrides_builtin(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
self, mock_prompts_dirs: tuple[Path, Path]
) -> None:
"""Custom prompts in .vibe/prompts/ should override built-in prompts.
@ -283,24 +259,9 @@ class TestAgentApplyToConfig:
project or user prompts directory must take priority over the
bundled SystemPrompt enum.
"""
project_prompts = tmp_path / "project" / ".vibe" / "prompts"
project_prompts.mkdir(parents=True)
project_prompts, _ = mock_prompts_dirs
(project_prompts / "explore.md").write_text("My custom explore prompt")
class _MockManager(HarnessFilesManager):
@property
def project_prompts_dirs(self) -> list[Path]:
return [project_prompts]
@property
def user_prompts_dirs(self) -> list[Path]:
return []
mock_manager = _MockManager(sources=("user",))
monkeypatch.setattr(
"vibe.core.prompts.get_harness_files_manager", lambda: mock_manager
)
config = VibeConfig(
system_prompt_id="explore",
include_project_context=False,
@ -308,6 +269,71 @@ class TestAgentApplyToConfig:
)
assert config.system_prompt == "My custom explore prompt"
def test_custom_compaction_prompt_found_in_global_when_missing_from_project(
self, mock_prompts_dirs: tuple[Path, Path]
) -> None:
_, global_prompts = mock_prompts_dirs
(global_prompts / "proofs.md").write_text("Global custom compaction prompt")
config = VibeConfig(
compaction_prompt_id="proofs",
include_project_context=False,
include_prompt_detail=False,
)
assert config.compaction_prompt == "Global custom compaction prompt"
def test_custom_compaction_prompt_overrides_builtin(
self, mock_prompts_dirs: tuple[Path, Path]
) -> None:
project_prompts, _ = mock_prompts_dirs
(project_prompts / "compact.md").write_text("My custom compact prompt")
config = VibeConfig(
compaction_prompt_id="compact",
include_project_context=False,
include_prompt_detail=False,
)
assert config.compaction_prompt == "My custom compact prompt"
def test_default_compaction_prompt_falls_back_to_builtin(
self, mock_prompts_dirs: tuple[Path, Path]
) -> None:
config = VibeConfig(include_project_context=False, include_prompt_detail=False)
assert config.compaction_prompt == UtilityPrompt.COMPACT.read()
def test_invalid_compaction_prompt_reports_setting_name(
self, mock_prompts_dirs: tuple[Path, Path]
) -> None:
project_prompts, user_prompts = mock_prompts_dirs
(project_prompts / "alpha.md").write_text("a")
(user_prompts / "beta.md").write_text("b")
with pytest.raises(ValueError) as exc_info:
VibeConfig(
compaction_prompt_id="unknown",
include_project_context=False,
include_prompt_detail=False,
)
error_text = str(exc_info.value)
assert "Invalid compaction_prompt_id value: 'unknown'" in error_text
assert 'available prompts ("compact")' in error_text
assert '(available: "alpha", "beta")' in error_text
@pytest.mark.parametrize(
"malicious_id",
["../../../etc/passwd", "..", ".", "subdir/compact", "back\\slash", ""],
)
def test_prompt_id_rejects_path_traversal(
self, mock_prompts_dirs: tuple[Path, Path], malicious_id: str
) -> None:
with pytest.raises(ValueError, match="must be a bare filename"):
VibeConfig(
compaction_prompt_id=malicious_id,
include_project_context=False,
include_prompt_detail=False,
)
class TestAgentProfileOverrides:
def test_default_agent_disables_exit_plan_mode(self) -> None:
@ -679,30 +705,12 @@ class TestAgentManagerFiltering:
class TestAgentLoopInitialization:
def test_agent_system_prompt_id_is_applied_on_init(
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
self, mock_prompts_dirs: tuple[Path, Path], monkeypatch: pytest.MonkeyPatch
) -> None:
project_prompts = tmp_path / "project" / ".vibe" / "prompts"
project_prompts.mkdir(parents=True)
global_prompts = tmp_path / "home" / ".vibe" / "prompts"
global_prompts.mkdir(parents=True)
_, global_prompts = mock_prompts_dirs
custom_prompt_content = "CUSTOM_AGENT_PROMPT_MARKER"
(global_prompts / "custom_agent.md").write_text(custom_prompt_content)
class _MockManager(HarnessFilesManager):
@property
def project_prompts_dirs(self) -> list[Path]:
return [project_prompts]
@property
def user_prompts_dirs(self) -> list[Path]:
return [global_prompts]
mock_manager = _MockManager(sources=("user",))
monkeypatch.setattr(
"vibe.core.prompts.get_harness_files_manager", lambda: mock_manager
)
custom_agent = AgentProfile(
name="custom_test_agent",
display_name="Custom Test",