tech-envision commited on
Commit
114361d
·
1 Parent(s): 09df150

document session registry

Browse files
Files changed (2) hide show
  1. README.md +5 -0
  2. 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._lock = asyncio.Lock()
53
- self._state = "idle"
54
- self._tool_task: asyncio.Task | None = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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