Spaces:
Runtime error
Runtime error
tech-envision
commited on
Commit
·
9f82d8d
1
Parent(s):
100e82d
feat(vm): persist containers across sessions
Browse files
README.md
CHANGED
@@ -13,8 +13,11 @@ conversations can be resumed with context. One example tool is included:
|
|
13 |
Execution happens asynchronously so the assistant can continue responding
|
14 |
while the command runs.
|
15 |
The VM is created when a chat session starts and reused for all subsequent
|
16 |
-
tool calls.
|
17 |
-
|
|
|
|
|
|
|
18 |
|
19 |
Sessions share state through an in-memory registry so that only one generation
|
20 |
can run at a time. Messages sent while a response is being produced are
|
@@ -77,6 +80,9 @@ back to ``python:3.11-slim``. This base image includes Python and ``pip`` so
|
|
77 |
packages can be installed immediately. The container has network access enabled
|
78 |
which allows fetching additional dependencies as needed.
|
79 |
|
|
|
|
|
|
|
80 |
To use a fully featured Ubuntu environment, build a custom Docker image and set
|
81 |
``VM_IMAGE`` to that image. An example ``docker/Dockerfile.vm`` is provided:
|
82 |
|
|
|
13 |
Execution happens asynchronously so the assistant can continue responding
|
14 |
while the command runs.
|
15 |
The VM is created when a chat session starts and reused for all subsequent
|
16 |
+
tool calls. When ``PERSIST_VMS`` is enabled (default), each user keeps the
|
17 |
+
same container across multiple chat sessions so any installed packages and
|
18 |
+
filesystem changes remain available. The environment includes Python and
|
19 |
+
``pip`` so complex tasks can be scripted using Python directly inside the
|
20 |
+
terminal.
|
21 |
|
22 |
Sessions share state through an in-memory registry so that only one generation
|
23 |
can run at a time. Messages sent while a response is being produced are
|
|
|
80 |
packages can be installed immediately. The container has network access enabled
|
81 |
which allows fetching additional dependencies as needed.
|
82 |
|
83 |
+
Set ``PERSIST_VMS=0`` to revert to the previous behaviour where containers are
|
84 |
+
stopped once no sessions are using them.
|
85 |
+
|
86 |
To use a fully featured Ubuntu environment, build a custom Docker image and set
|
87 |
``VM_IMAGE`` to that image. An example ``docker/Dockerfile.vm`` is provided:
|
88 |
|
run.py
CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
3 |
import asyncio
|
4 |
|
5 |
from src.chat import ChatSession
|
|
|
6 |
|
7 |
|
8 |
async def _main() -> None:
|
@@ -24,3 +25,5 @@ if __name__ == "__main__":
|
|
24 |
asyncio.run(_main())
|
25 |
except KeyboardInterrupt:
|
26 |
pass
|
|
|
|
|
|
3 |
import asyncio
|
4 |
|
5 |
from src.chat import ChatSession
|
6 |
+
from src.vm import VMRegistry
|
7 |
|
8 |
|
9 |
async def _main() -> None:
|
|
|
25 |
asyncio.run(_main())
|
26 |
except KeyboardInterrupt:
|
27 |
pass
|
28 |
+
finally:
|
29 |
+
VMRegistry.shutdown_all()
|
src/config.py
CHANGED
@@ -10,6 +10,7 @@ MAX_TOOL_CALL_DEPTH: Final[int] = 5
|
|
10 |
NUM_CTX: Final[int] = int(os.getenv("OLLAMA_NUM_CTX", "32000"))
|
11 |
UPLOAD_DIR: Final[str] = os.getenv("UPLOAD_DIR", str(Path.cwd() / "uploads"))
|
12 |
VM_IMAGE: Final[str] = os.getenv("VM_IMAGE", "python:3.11")
|
|
|
13 |
|
14 |
SYSTEM_PROMPT: Final[str] = (
|
15 |
"You are Starlette, a professional AI assistant with advanced tool orchestration. "
|
|
|
10 |
NUM_CTX: Final[int] = int(os.getenv("OLLAMA_NUM_CTX", "32000"))
|
11 |
UPLOAD_DIR: Final[str] = os.getenv("UPLOAD_DIR", str(Path.cwd() / "uploads"))
|
12 |
VM_IMAGE: Final[str] = os.getenv("VM_IMAGE", "python:3.11")
|
13 |
+
PERSIST_VMS: Final[bool] = os.getenv("PERSIST_VMS", "1") == "1"
|
14 |
|
15 |
SYSTEM_PROMPT: Final[str] = (
|
16 |
"You are Starlette, a professional AI assistant with advanced tool orchestration. "
|
src/vm.py
CHANGED
@@ -8,7 +8,7 @@ from pathlib import Path
|
|
8 |
|
9 |
from threading import Lock
|
10 |
|
11 |
-
from .config import UPLOAD_DIR, VM_IMAGE
|
12 |
|
13 |
from .log import get_logger
|
14 |
|
@@ -180,6 +180,18 @@ class VMRegistry:
|
|
180 |
|
181 |
cls._counts[username] -= 1
|
182 |
if cls._counts[username] <= 0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
vm.stop()
|
184 |
-
|
185 |
-
|
|
|
8 |
|
9 |
from threading import Lock
|
10 |
|
11 |
+
from .config import UPLOAD_DIR, VM_IMAGE, PERSIST_VMS
|
12 |
|
13 |
from .log import get_logger
|
14 |
|
|
|
180 |
|
181 |
cls._counts[username] -= 1
|
182 |
if cls._counts[username] <= 0:
|
183 |
+
cls._counts[username] = 0
|
184 |
+
if not PERSIST_VMS:
|
185 |
+
vm.stop()
|
186 |
+
del cls._vms[username]
|
187 |
+
del cls._counts[username]
|
188 |
+
|
189 |
+
@classmethod
|
190 |
+
def shutdown_all(cls) -> None:
|
191 |
+
"""Stop and remove all managed VMs."""
|
192 |
+
|
193 |
+
with cls._lock:
|
194 |
+
for vm in cls._vms.values():
|
195 |
vm.stop()
|
196 |
+
cls._vms.clear()
|
197 |
+
cls._counts.clear()
|