Spaces:
Runtime error
Runtime error
tech-envision
commited on
Commit
·
114361d
1
Parent(s):
09df150
document session registry
Browse files- README.md +5 -0
- src/chat.py +42 -5
README.md
CHANGED
|
@@ -12,6 +12,11 @@ conversations can be resumed with context. One example tool is included:
|
|
| 12 |
responding while they execute. The VM is created when a chat session starts
|
| 13 |
and reused for all subsequent tool calls.
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
The application injects a robust system prompt on each request. The prompt
|
| 16 |
guides the model to plan tool usage, execute commands sequentially and
|
| 17 |
verify results before replying. It is **not** stored in the chat history but is
|
|
|
|
| 12 |
responding while they execute. The VM is created when a chat session starts
|
| 13 |
and reused for all subsequent tool calls.
|
| 14 |
|
| 15 |
+
Sessions share state through an in-memory registry so that only one generation
|
| 16 |
+
can run at a time. Messages sent while a response is being produced are
|
| 17 |
+
ignored unless the assistant is waiting for a tool result—in that case the
|
| 18 |
+
pending response is cancelled and replaced with the new request.
|
| 19 |
+
|
| 20 |
The application injects a robust system prompt on each request. The prompt
|
| 21 |
guides the model to plan tool usage, execute commands sequentially and
|
| 22 |
verify results before replying. It is **not** stored in the chat history but is
|
src/chat.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from typing import List, AsyncIterator
|
|
|
|
| 4 |
import json
|
| 5 |
import asyncio
|
| 6 |
import shutil
|
|
@@ -29,6 +30,27 @@ from .schema import Msg
|
|
| 29 |
from .tools import execute_terminal, execute_terminal_async, set_vm
|
| 30 |
from .vm import VMRegistry
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
_LOG = get_logger(__name__)
|
| 33 |
|
| 34 |
|
|
@@ -49,9 +71,26 @@ class ChatSession:
|
|
| 49 |
)
|
| 50 |
self._vm = None
|
| 51 |
self._messages: List[Msg] = self._load_history()
|
| 52 |
-
self.
|
| 53 |
-
self.
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
async def __aenter__(self) -> "ChatSession":
|
| 57 |
self._vm = VMRegistry.acquire(self._user.username)
|
|
@@ -365,5 +404,3 @@ class ChatSession:
|
|
| 365 |
continue
|
| 366 |
if part.message.content:
|
| 367 |
yield part.message.content
|
| 368 |
-
|
| 369 |
-
|
|
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from typing import List, AsyncIterator
|
| 4 |
+
from dataclasses import dataclass, field
|
| 5 |
import json
|
| 6 |
import asyncio
|
| 7 |
import shutil
|
|
|
|
| 30 |
from .tools import execute_terminal, execute_terminal_async, set_vm
|
| 31 |
from .vm import VMRegistry
|
| 32 |
|
| 33 |
+
|
| 34 |
+
@dataclass
|
| 35 |
+
class _SessionData:
|
| 36 |
+
"""Shared state for each conversation session."""
|
| 37 |
+
|
| 38 |
+
lock: asyncio.Lock = field(default_factory=asyncio.Lock)
|
| 39 |
+
state: str = "idle"
|
| 40 |
+
tool_task: asyncio.Task | None = None
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
_SESSION_DATA: dict[int, _SessionData] = {}
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def _get_session_data(conv_id: int) -> _SessionData:
|
| 47 |
+
data = _SESSION_DATA.get(conv_id)
|
| 48 |
+
if data is None:
|
| 49 |
+
data = _SessionData()
|
| 50 |
+
_SESSION_DATA[conv_id] = data
|
| 51 |
+
return data
|
| 52 |
+
|
| 53 |
+
|
| 54 |
_LOG = get_logger(__name__)
|
| 55 |
|
| 56 |
|
|
|
|
| 71 |
)
|
| 72 |
self._vm = None
|
| 73 |
self._messages: List[Msg] = self._load_history()
|
| 74 |
+
self._data = _get_session_data(self._conversation.id)
|
| 75 |
+
self._lock = self._data.lock
|
| 76 |
+
|
| 77 |
+
# Shared state properties -------------------------------------------------
|
| 78 |
+
|
| 79 |
+
@property
|
| 80 |
+
def _state(self) -> str:
|
| 81 |
+
return self._data.state
|
| 82 |
+
|
| 83 |
+
@_state.setter
|
| 84 |
+
def _state(self, value: str) -> None:
|
| 85 |
+
self._data.state = value
|
| 86 |
+
|
| 87 |
+
@property
|
| 88 |
+
def _tool_task(self) -> asyncio.Task | None:
|
| 89 |
+
return self._data.tool_task
|
| 90 |
+
|
| 91 |
+
@_tool_task.setter
|
| 92 |
+
def _tool_task(self, task: asyncio.Task | None) -> None:
|
| 93 |
+
self._data.tool_task = task
|
| 94 |
|
| 95 |
async def __aenter__(self) -> "ChatSession":
|
| 96 |
self._vm = VMRegistry.acquire(self._user.username)
|
|
|
|
| 404 |
continue
|
| 405 |
if part.message.content:
|
| 406 |
yield part.message.content
|
|
|
|
|
|