vibe/vibe/acp/session.py
Clément Drouin 632ea8c032
v2.9.0 (#641)
Co-authored-by: Antoine <33425718+anth2o@users.noreply.github.com>
Co-authored-by: Bastien <bastien.baret@gmail.com>
Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai>
Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com>
Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai>
Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai>
Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com>
Co-authored-by: Nelson PROIA <144663685+Nelson-PROIA@users.noreply.github.com>
Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai>
Co-authored-by: Quentin <quentin.torroba@mistral.ai>
Co-authored-by: Robin Gullo <robin.gullo@mistral.ai>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
2026-04-28 17:44:07 +02:00

75 lines
2.6 KiB
Python

from __future__ import annotations
import asyncio
from collections.abc import Coroutine
from typing import Any
from vibe.acp.commands import AcpCommandRegistry
from vibe.core.agent_loop import AgentLoop
class AcpSessionLoop:
"""Holds the state for a single ACP session.
All session-scoped async work (background updates, the prompt task)
is tracked internally. ``close`` cancels everything;
``cancel_prompt`` cancels only the active prompt.
"""
def __init__(
self, *, id: str, agent_loop: AgentLoop, command_registry: AcpCommandRegistry
) -> None:
self.id = id
self.agent_loop = agent_loop
self.command_registry = command_registry
self._closed = False
self._tasks: set[asyncio.Task[None]] = set()
self._prompt_task: asyncio.Task[None] | None = None
# -- public API ------------------------------------------------------------
@property
def prompt_task(self) -> asyncio.Task[None] | None:
return self._prompt_task
def spawn(self, coro: Coroutine[Any, Any, None]) -> asyncio.Task[None] | None:
"""Launch a background coroutine tied to this session."""
if self._closed:
coro.close()
return None
task = asyncio.create_task(coro)
self._tasks.add(task)
task.add_done_callback(self._tasks.discard)
return task
def set_prompt_task(self, coro: Coroutine[Any, Any, None]) -> asyncio.Task[None]:
"""Create the prompt task. Only one may be active at a time."""
task = asyncio.create_task(coro)
self._prompt_task = task
self._tasks.add(task)
task.add_done_callback(self._tasks.discard)
task.add_done_callback(lambda _: self._clear_prompt_task(task))
return task
async def cancel_prompt(self) -> None:
"""Cancel the active prompt task, if any."""
task = self._prompt_task
if task is None or task.done():
return
task.cancel()
await asyncio.gather(task, return_exceptions=True)
async def close(self) -> None:
"""Cancel all tasks (prompt + background) and mark session closed."""
self._closed = True
for t in self._tasks:
t.cancel()
await asyncio.gather(*self._tasks, return_exceptions=True)
self._tasks.clear()
self._prompt_task = None
# -- private ---------------------------------------------------------------
def _clear_prompt_task(self, task: asyncio.Task[None]) -> None:
if self._prompt_task is task:
self._prompt_task = None