diff --git a/.vscode/launch.json b/.vscode/launch.json index 5cbcde4..a2dbf24 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,5 +1,5 @@ { - "version": "1.3.2", + "version": "1.3.3", "configurations": [ { "name": "ACP Server", diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f1639..11a247f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.3.3] - 2025-12-26 + +### Fixed + +- Fix config desyncing issues + ## [1.3.2] - 2025-12-24 ### Added diff --git a/distribution/zed/extension.toml b/distribution/zed/extension.toml index 958eacc..1b2715e 100644 --- a/distribution/zed/extension.toml +++ b/distribution/zed/extension.toml @@ -1,7 +1,7 @@ id = "mistral-vibe" name = "Mistral Vibe" description = "Mistral's open-source coding assistant" -version = "1.3.2" +version = "1.3.3" schema_version = 1 authors = ["Mistral AI"] repository = "https://github.com/mistralai/mistral-vibe" @@ -11,25 +11,25 @@ name = "Mistral Vibe" icon = "./icons/mistral_vibe.svg" [agent_servers.mistral-vibe.targets.darwin-aarch64] -archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.2/vibe-acp-darwin-aarch64-1.3.2.zip" +archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.3/vibe-acp-darwin-aarch64-1.3.3.zip" cmd = "./vibe-acp" [agent_servers.mistral-vibe.targets.darwin-x86_64] -archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.2/vibe-acp-darwin-x86_64-1.3.2.zip" +archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.3/vibe-acp-darwin-x86_64-1.3.3.zip" cmd = "./vibe-acp" [agent_servers.mistral-vibe.targets.linux-aarch64] -archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.2/vibe-acp-linux-aarch64-1.3.2.zip" +archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.3/vibe-acp-linux-aarch64-1.3.3.zip" cmd = "./vibe-acp" [agent_servers.mistral-vibe.targets.linux-x86_64] -archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.2/vibe-acp-linux-x86_64-1.3.2.zip" +archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.3/vibe-acp-linux-x86_64-1.3.3.zip" cmd = "./vibe-acp" [agent_servers.mistral-vibe.targets.windows-aarch64] -archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.2/vibe-acp-windows-aarch64-1.3.2.zip" +archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.3/vibe-acp-windows-aarch64-1.3.3.zip" cmd = "./vibe-acp.exe" [agent_servers.mistral-vibe.targets.windows-x86_64] -archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.2/vibe-acp-windows-x86_64-1.3.2.zip" +archive = "https://github.com/mistralai/mistral-vibe/releases/download/v1.3.3/vibe-acp-windows-x86_64-1.3.3.zip" cmd = "./vibe-acp.exe" diff --git a/pyproject.toml b/pyproject.toml index 9a09604..8df8936 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mistral-vibe" -version = "1.3.2" +version = "1.3.3" description = "Minimal CLI coding agent by Mistral" readme = "README.md" requires-python = ">=3.12" diff --git a/tests/acp/test_initialize.py b/tests/acp/test_initialize.py index 34eb8a2..bf3da93 100644 --- a/tests/acp/test_initialize.py +++ b/tests/acp/test_initialize.py @@ -41,7 +41,7 @@ class TestACPInitialize: ), ) assert response.agentInfo == Implementation( - name="@mistralai/mistral-vibe", title="Mistral Vibe", version="1.3.2" + name="@mistralai/mistral-vibe", title="Mistral Vibe", version="1.3.3" ) assert response.authMethods == [] @@ -63,7 +63,7 @@ class TestACPInitialize: ), ) assert response.agentInfo == Implementation( - name="@mistralai/mistral-vibe", title="Mistral Vibe", version="1.3.2" + name="@mistralai/mistral-vibe", title="Mistral Vibe", version="1.3.3" ) assert response.authMethods is not None diff --git a/tests/skills/test_manager.py b/tests/skills/test_manager.py index 90d9da6..1780e39 100644 --- a/tests/skills/test_manager.py +++ b/tests/skills/test_manager.py @@ -20,7 +20,7 @@ def config() -> VibeConfig: @pytest.fixture def skill_manager(config: VibeConfig) -> SkillManager: - return SkillManager(config) + return SkillManager(lambda: config) class TestSkillManagerDiscovery: @@ -38,7 +38,7 @@ class TestSkillManagerDiscovery: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) assert "test-skill" in manager.available_skills assert manager.available_skills["test-skill"].description == "A test skill" @@ -54,7 +54,7 @@ class TestSkillManagerDiscovery: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) assert len(manager.available_skills) == 3 assert "skill-one" in manager.available_skills @@ -76,7 +76,7 @@ class TestSkillManagerDiscovery: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skills = manager.available_skills assert len(skills) == 1 @@ -96,7 +96,7 @@ class TestSkillManagerDiscovery: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skills = manager.available_skills assert len(skills) == 1 @@ -121,7 +121,7 @@ class TestSkillManagerParsing: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skill = manager.get_skill("full-skill") assert skill is not None @@ -141,7 +141,7 @@ class TestSkillManagerParsing: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skill = manager.get_skill("test-skill") assert skill is not None @@ -163,7 +163,7 @@ class TestSkillManagerParsing: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skills = manager.available_skills assert len(skills) == 1 @@ -185,7 +185,7 @@ class TestSkillManagerParsing: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skills = manager.available_skills assert len(skills) == 1 @@ -209,7 +209,7 @@ class TestSkillManagerSearchPaths: include_project_context=False, skill_paths=[skills_dir_1, skills_dir_2], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skills = manager.available_skills assert len(skills) == 2 @@ -232,7 +232,7 @@ class TestSkillManagerSearchPaths: include_project_context=False, skill_paths=[skills_dir_1, skills_dir_2], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skills = manager.available_skills assert len(skills) == 1 @@ -249,7 +249,7 @@ class TestSkillManagerSearchPaths: include_project_context=False, skill_paths=[skills_dir, tmp_path / "nonexistent"], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) assert len(manager.available_skills) == 1 assert "valid-skill" in manager.available_skills @@ -265,7 +265,7 @@ class TestSkillManagerGetSkill: include_project_context=False, skill_paths=[skills_dir], ) - manager = SkillManager(config) + manager = SkillManager(lambda: config) skill = manager.get_skill("test-skill") assert skill is not None diff --git a/tests/test_system_prompt.py b/tests/test_system_prompt.py index ee54496..b0bd51e 100644 --- a/tests/test_system_prompt.py +++ b/tests/test_system_prompt.py @@ -22,7 +22,7 @@ def test_get_universal_system_prompt_includes_windows_prompt_on_windows( include_model_info=False, include_commit_signature=False, ) - tool_manager = ToolManager(config) + tool_manager = ToolManager(lambda: config) prompt = get_universal_system_prompt(tool_manager, config) diff --git a/tests/tools/test_manager_get_tool_config.py b/tests/tools/test_manager_get_tool_config.py index d5a40f5..6f2de19 100644 --- a/tests/tools/test_manager_get_tool_config.py +++ b/tests/tools/test_manager_get_tool_config.py @@ -18,7 +18,7 @@ def config(): @pytest.fixture def tool_manager(config): - return ToolManager(config) + return ToolManager(lambda: config) def test_returns_default_config_when_no_overrides(tool_manager): @@ -39,7 +39,7 @@ def test_merges_user_overrides_with_defaults(): include_project_context=False, tools={"bash": BaseToolConfig(permission=ToolPermission.ALWAYS)}, ) - manager = ToolManager(vibe_config) + manager = ToolManager(lambda: vibe_config) config = manager.get_tool_config("bash") @@ -58,7 +58,7 @@ def test_preserves_tool_specific_fields_from_overrides(): tools={"bash": BaseToolConfig(permission=ToolPermission.ASK)}, ) vibe_config.tools["bash"].__pydantic_extra__ = {"default_timeout": 600} - manager = ToolManager(vibe_config) + manager = ToolManager(lambda: vibe_config) config = manager.get_tool_config("bash") @@ -80,7 +80,7 @@ def test_applies_workdir_from_vibe_config(tmp_path): include_project_context=False, workdir=tmp_path, ) - manager = ToolManager(vibe_config) + manager = ToolManager(lambda: vibe_config) config = manager.get_tool_config("bash") diff --git a/uv.lock b/uv.lock index cc2c935..1546df8 100644 --- a/uv.lock +++ b/uv.lock @@ -661,7 +661,7 @@ wheels = [ [[package]] name = "mistral-vibe" -version = "1.3.2" +version = "1.3.3" source = { editable = "." } dependencies = [ { name = "agent-client-protocol" }, diff --git a/vibe/__init__.py b/vibe/__init__.py index 7b76d30..fce9a53 100644 --- a/vibe/__init__.py +++ b/vibe/__init__.py @@ -3,4 +3,4 @@ from __future__ import annotations from pathlib import Path VIBE_ROOT = Path(__file__).parent -__version__ = "1.3.2" +__version__ = "1.3.3" diff --git a/vibe/cli/textual_ui/app.py b/vibe/cli/textual_ui/app.py index a5f0b73..6174ae9 100644 --- a/vibe/cli/textual_ui/app.py +++ b/vibe/cli/textual_ui/app.py @@ -74,7 +74,7 @@ class BottomApp(StrEnum): Input = auto() -class VibeApp(App): +class VibeApp(App): # noqa: PLR0904 ENABLE_COMMAND_PALETTE = False CSS_PATH = "app.tcss" @@ -104,7 +104,7 @@ class VibeApp(App): **kwargs: Any, ) -> None: super().__init__(**kwargs) - self.config = config + self._config = config self._current_agent_mode = initial_mode self.enable_streaming = enable_streaming self.agent: Agent | None = None @@ -147,6 +147,10 @@ class VibeApp(App): self._last_escape_time: float | None = None self._terminal_theme = capture_terminal_theme() + @property + def config(self) -> VibeConfig: + return self.agent.config if self.agent else self._config + def compose(self) -> ComposeResult: with VerticalScroll(id="chat"): yield WelcomeBanner(self.config) @@ -704,8 +708,8 @@ class VibeApp(App): if self.agent: await self.agent.reload_with_initial_messages(config=new_config) - - self.config = new_config + else: + self._config = new_config if self._context_progress: if self.config.auto_compact_threshold > 0: current_tokens = ( diff --git a/vibe/core/agent.py b/vibe/core/agent.py index 581b886..f6caf36 100644 --- a/vibe/core/agent.py +++ b/vibe/core/agent.py @@ -104,8 +104,8 @@ class Agent: self._max_turns = max_turns self._max_price = max_price - self.tool_manager = ToolManager(config) - self.skill_manager = SkillManager(config) + self.tool_manager = ToolManager(lambda: self.config) + self.skill_manager = SkillManager(lambda: self.config) self.format_handler = APIToolFormatHandler() self.backend_factory = lambda: backend or self._select_backend() @@ -870,8 +870,8 @@ class Agent: if max_price is not None: self._max_price = max_price - self.tool_manager = ToolManager(self.config) - self.skill_manager = SkillManager(self.config) + self.tool_manager = ToolManager(lambda: self.config) + self.skill_manager = SkillManager(lambda: self.config) new_system_prompt = get_universal_system_prompt( self.tool_manager, self.config, self.skill_manager diff --git a/vibe/core/skills/manager.py b/vibe/core/skills/manager.py index a837622..b6107a9 100644 --- a/vibe/core/skills/manager.py +++ b/vibe/core/skills/manager.py @@ -1,5 +1,6 @@ from __future__ import annotations +from collections.abc import Callable from logging import getLogger from pathlib import Path from typing import TYPE_CHECKING @@ -16,9 +17,9 @@ logger = getLogger("vibe") class SkillManager: - def __init__(self, config: VibeConfig) -> None: - self._config = config - self._search_paths = self._compute_search_paths(config) + def __init__(self, config_getter: Callable[[], VibeConfig]) -> None: + self._config_getter = config_getter + self._search_paths = self._compute_search_paths(self._config) self.available_skills = self._discover_skills() if self.available_skills: @@ -28,6 +29,10 @@ class SkillManager: len(self._search_paths), ) + @property + def _config(self) -> VibeConfig: + return self._config_getter() + @staticmethod def _compute_search_paths(config: VibeConfig) -> list[Path]: paths: list[Path] = [] diff --git a/vibe/core/tools/manager.py b/vibe/core/tools/manager.py index 5c81547..f968225 100644 --- a/vibe/core/tools/manager.py +++ b/vibe/core/tools/manager.py @@ -1,6 +1,6 @@ from __future__ import annotations -from collections.abc import Iterator +from collections.abc import Callable, Iterator import importlib.util import inspect from logging import getLogger @@ -38,16 +38,20 @@ class ToolManager: should have its own ToolManager instance. """ - def __init__(self, config: VibeConfig) -> None: - self._config = config + def __init__(self, config_getter: Callable[[], VibeConfig]) -> None: + self._config_getter = config_getter self._instances: dict[str, BaseTool] = {} - self._search_paths: list[Path] = self._compute_search_paths(config) + self._search_paths: list[Path] = self._compute_search_paths(self._config) self._available: dict[str, type[BaseTool]] = { cls.get_name(): cls for cls in self._iter_tool_classes(self._search_paths) } self._integrate_mcp() + @property + def _config(self) -> VibeConfig: + return self._config_getter() + @staticmethod def _compute_search_paths(config: VibeConfig) -> list[Path]: paths: list[Path] = [DEFAULT_TOOL_DIR.path]