mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-11 16:26:02 +00:00
feat(box): add BoxProfile with resource limits and improved output truncation
- Implement head+tail output truncation (60/40 split) so LLM sees both
beginning and final results; add streaming byte-limited reads in backend
to prevent unbounded memory usage (_MAX_RAW_OUTPUT_BYTES = 1MB)
- Define BoxProfile model with locked fields and max_timeout_sec clamping
- Add four built-in profiles: default, offline_readonly, network_basic,
network_extended with differentiated resource and security constraints
- Add resource limit fields to BoxSpec (cpus, memory_mb, pids_limit,
read_only_rootfs) and pass corresponding container CLI flags
(--cpus, --memory, --pids-limit, --read-only, --tmpfs)
- Profile loaded from config (box.profile), applied in service layer
before BoxSpec validation; locked fields cannot be overridden by
tool-call parameters
This commit is contained in:
@@ -9,6 +9,8 @@ from .backend import BaseSandboxBackend, DockerBackend, PodmanBackend
|
||||
from .errors import BoxBackendUnavailableError, BoxSessionConflictError
|
||||
from .models import BoxExecutionResult, BoxExecutionStatus, BoxSessionInfo, BoxSpec
|
||||
|
||||
_UTC = dt.timezone.utc
|
||||
|
||||
|
||||
@dataclasses.dataclass(slots=True)
|
||||
class _RuntimeSession:
|
||||
@@ -48,7 +50,7 @@ class BoxRuntime:
|
||||
result = await (await self._get_backend()).exec(session.info, spec)
|
||||
|
||||
async with self._lock:
|
||||
now = dt.datetime.now(dt.UTC)
|
||||
now = dt.datetime.now(_UTC)
|
||||
if spec.session_id in self._sessions:
|
||||
self._sessions[spec.session_id].info.last_used_at = now
|
||||
|
||||
@@ -70,7 +72,7 @@ class BoxRuntime:
|
||||
existing = self._sessions.get(spec.session_id)
|
||||
if existing is not None:
|
||||
self._assert_session_compatible(existing.info, spec)
|
||||
existing.info.last_used_at = dt.datetime.now(dt.UTC)
|
||||
existing.info.last_used_at = dt.datetime.now(_UTC)
|
||||
self.logger.info(
|
||||
'LangBot Box session reused: '
|
||||
f'session_id={spec.session_id} '
|
||||
@@ -121,7 +123,7 @@ class BoxRuntime:
|
||||
if self.session_ttl_sec <= 0:
|
||||
return
|
||||
|
||||
deadline = dt.datetime.now(dt.UTC) - dt.timedelta(seconds=self.session_ttl_sec)
|
||||
deadline = dt.datetime.now(_UTC) - dt.timedelta(seconds=self.session_ttl_sec)
|
||||
expired_session_ids = [
|
||||
session_id
|
||||
for session_id, session in self._sessions.items()
|
||||
@@ -164,3 +166,19 @@ class BoxRuntime:
|
||||
raise BoxSessionConflictError(
|
||||
f'sandbox_exec session {spec.session_id} already exists with host_path_mode={session.host_path_mode.value}'
|
||||
)
|
||||
if session.cpus != spec.cpus:
|
||||
raise BoxSessionConflictError(
|
||||
f'sandbox_exec session {spec.session_id} already exists with cpus={session.cpus}'
|
||||
)
|
||||
if session.memory_mb != spec.memory_mb:
|
||||
raise BoxSessionConflictError(
|
||||
f'sandbox_exec session {spec.session_id} already exists with memory_mb={session.memory_mb}'
|
||||
)
|
||||
if session.pids_limit != spec.pids_limit:
|
||||
raise BoxSessionConflictError(
|
||||
f'sandbox_exec session {spec.session_id} already exists with pids_limit={session.pids_limit}'
|
||||
)
|
||||
if session.read_only_rootfs != spec.read_only_rootfs:
|
||||
raise BoxSessionConflictError(
|
||||
f'sandbox_exec session {spec.session_id} already exists with read_only_rootfs={session.read_only_rootfs}'
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user