Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai>
Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai>
Co-Authored-By: Kracekumar <kracethekingmaker@gmail.com>
This commit is contained in:
Quentin 2025-12-14 00:54:42 +01:00 committed by Mathias Gesbert
parent 661588de0c
commit d8dbeeb31e
91 changed files with 4521 additions and 873 deletions

View file

@ -46,17 +46,23 @@ from acp.schema import (
)
from pydantic import BaseModel, ConfigDict
from vibe import VIBE_ROOT
from vibe import VIBE_ROOT, __version__
from vibe.acp.tools.base import BaseAcpTool
from vibe.acp.tools.session_update import (
tool_call_session_update,
tool_result_session_update,
)
from vibe.acp.utils import TOOL_OPTIONS, ToolOption, VibeSessionMode
from vibe.core import __version__
from vibe.acp.utils import (
TOOL_OPTIONS,
ToolOption,
acp_to_agent_mode,
get_all_acp_session_modes,
is_valid_acp_mode,
)
from vibe.core.agent import Agent as VibeAgent
from vibe.core.autocompletion.path_prompt_adapter import render_path_prompt
from vibe.core.config import MissingAPIKeyError, VibeConfig, load_api_keys_from_env
from vibe.core.modes import AgentMode
from vibe.core.tools.base import BaseToolConfig, ToolPermission
from vibe.core.types import (
ApprovalResponse,
@ -72,7 +78,6 @@ class AcpSession(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
id: str
agent: VibeAgent
mode_id: VibeSessionMode = VibeSessionMode.APPROVAL_REQUIRED
task: asyncio.Task[None] | None = None
@ -154,9 +159,11 @@ class VibeAcpAgent(AcpAgent):
async def newSession(self, params: NewSessionRequest) -> NewSessionResponse:
capability_disabled_tools = self._get_disabled_tools_from_capabilities()
load_api_keys_from_env()
cwd = Path(params.cwd)
try:
config = VibeConfig.load(
workdir=Path(params.cwd),
workdir=cwd,
tool_paths=[str(VIBE_ROOT / "acp" / "tools" / "builtins")],
disabled_tools=capability_disabled_tools,
)
@ -165,7 +172,7 @@ class VibeAcpAgent(AcpAgent):
"message": "You must be authenticated before creating a new session"
}) from e
agent = VibeAgent(config=config, auto_approve=False, enable_streaming=True)
agent = VibeAgent(config=config, mode=AgentMode.DEFAULT, enable_streaming=True)
# NOTE: For now, we pin session.id to agent.session_id right after init time.
# We should just use agent.session_id everywhere, but it can still change during
# session lifetime (e.g. agent.compact is called).
@ -188,8 +195,8 @@ class VibeAcpAgent(AcpAgent):
],
),
modes=SessionModeState(
currentModeId=session.mode_id,
availableModes=VibeSessionMode.get_all_acp_session_modes(),
currentModeId=session.agent.mode.value,
availableModes=get_all_acp_session_modes(),
),
)
return response
@ -280,11 +287,21 @@ class VibeAcpAgent(AcpAgent):
) -> SetSessionModeResponse | None:
session = self._get_session(params.sessionId)
if not VibeSessionMode.is_valid(params.modeId):
if not is_valid_acp_mode(params.modeId):
return None
session.mode_id = VibeSessionMode(params.modeId)
session.agent.auto_approve = params.modeId == VibeSessionMode.AUTO_APPROVE
new_mode = acp_to_agent_mode(params.modeId)
if new_mode is None:
return None
await session.agent.switch_mode(new_mode)
if new_mode.auto_approve:
session.agent.approval_callback = None
else:
session.agent.set_approval_callback(
self._create_approval_callback(session.id)
)
return SetSessionModeResponse()

View file

@ -4,8 +4,8 @@ import argparse
from dataclasses import dataclass
import sys
from vibe.acp.acp_agent import run_acp_server
from vibe.setup.onboarding import run_onboarding
from vibe import __version__
from vibe.core.paths.config_paths import unlock_config_paths
# Configure line buffering for subprocess communication
sys.stdout.reconfigure(line_buffering=True) # pyright: ignore[reportAttributeAccessIssue]
@ -20,12 +20,20 @@ class Arguments:
def parse_arguments() -> Arguments:
parser = argparse.ArgumentParser(description="Run Mistral Vibe in ACP mode")
parser.add_argument(
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
)
parser.add_argument("--setup", action="store_true", help="Setup API key and exit")
args = parser.parse_args()
return Arguments(setup=args.setup)
def main() -> None:
unlock_config_paths()
from vibe.acp.acp_agent import run_acp_server
from vibe.setup.onboarding import run_onboarding
args = parse_arguments()
if args.setup:
run_onboarding()

View file

@ -1,47 +1,11 @@
from __future__ import annotations
import enum
from enum import StrEnum
from typing import Literal, cast
from acp.schema import PermissionOption, SessionMode
class VibeSessionMode(enum.StrEnum):
APPROVAL_REQUIRED = enum.auto()
AUTO_APPROVE = enum.auto()
def to_acp_session_mode(self) -> SessionMode:
match self:
case self.APPROVAL_REQUIRED:
return SessionMode(
id=VibeSessionMode.APPROVAL_REQUIRED,
name="Approval Required",
description="Requires user approval for tool executions",
)
case self.AUTO_APPROVE:
return SessionMode(
id=VibeSessionMode.AUTO_APPROVE,
name="Auto Approve",
description="Automatically approves all tool executions",
)
@classmethod
def from_acp_session_mode(cls, session_mode: SessionMode) -> VibeSessionMode | None:
if not cls.is_valid(session_mode.id):
return None
return cls(session_mode.id)
@classmethod
def is_valid(cls, mode_id: str) -> bool:
try:
return cls(mode_id).to_acp_session_mode() is not None
except (ValueError, KeyError):
return False
@classmethod
def get_all_acp_session_modes(cls) -> list[SessionMode]:
return [mode.to_acp_session_mode() for mode in cls]
from vibe.core.modes import MODE_CONFIGS, AgentMode
class ToolOption(StrEnum):
@ -68,3 +32,22 @@ TOOL_OPTIONS = [
kind=cast(Literal["reject_once"], ToolOption.REJECT_ONCE),
),
]
def agent_mode_to_acp(mode: AgentMode) -> SessionMode:
config = MODE_CONFIGS[mode]
return SessionMode(
id=mode.value, name=config.display_name, description=config.description
)
def acp_to_agent_mode(mode_id: str) -> AgentMode | None:
return AgentMode.from_string(mode_id)
def is_valid_acp_mode(mode_id: str) -> bool:
return AgentMode.from_string(mode_id) is not None
def get_all_acp_session_modes() -> list[SessionMode]:
return [agent_mode_to_acp(mode) for mode in AgentMode]