feat: enhance agent orchestration, knowledge flow and UI refinements

This commit is contained in:
2026-03-29 20:31:13 +08:00
parent d85cb9cf35
commit e0fe3ca623
301 changed files with 1197804 additions and 7863 deletions

View File

@@ -1,4 +1,8 @@
from datetime import datetime, UTC
from time import monotonic
import platform
import socket
import subprocess
try:
import psutil
@@ -7,21 +11,119 @@ except ModuleNotFoundError: # pragma: no cover - optional runtime dependency fa
class SystemService:
_last_net_bytes_sent: int | None = None
_last_net_bytes_recv: int | None = None
_last_net_sample_at: float | None = None
def _get_network_rates(self) -> tuple[float, float]:
counters = psutil.net_io_counters()
now = monotonic()
if (
self.__class__._last_net_sample_at is None
or self.__class__._last_net_bytes_sent is None
or self.__class__._last_net_bytes_recv is None
):
self.__class__._last_net_bytes_sent = counters.bytes_sent
self.__class__._last_net_bytes_recv = counters.bytes_recv
self.__class__._last_net_sample_at = now
return 0.0, 0.0
elapsed = max(now - self.__class__._last_net_sample_at, 1e-6)
upload_bps = max(counters.bytes_sent - self.__class__._last_net_bytes_sent, 0) / elapsed
download_bps = max(counters.bytes_recv - self.__class__._last_net_bytes_recv, 0) / elapsed
self.__class__._last_net_bytes_sent = counters.bytes_sent
self.__class__._last_net_bytes_recv = counters.bytes_recv
self.__class__._last_net_sample_at = now
return round(upload_bps, 1), round(download_bps, 1)
def _get_gpu_status(self) -> dict:
empty = {
'gpu_name': None,
'gpu_memory_total_mb': None,
'gpu_memory_used_mb': None,
'gpu_util_percent': None,
}
try:
result = subprocess.run(
[
'nvidia-smi',
'--query-gpu=name,memory.total,memory.used,utilization.gpu',
'--format=csv,noheader,nounits',
],
capture_output=True,
text=True,
encoding='utf-8',
timeout=2,
check=False,
)
except (FileNotFoundError, subprocess.SubprocessError, OSError):
return empty
if result.returncode != 0 or not result.stdout.strip():
return empty
first_line = result.stdout.strip().splitlines()[0]
parts = [part.strip() for part in first_line.split(',')]
if len(parts) < 4:
return empty
def parse_number(value: str) -> float | None:
try:
return float(value)
except (TypeError, ValueError):
return None
return {
'gpu_name': parts[0] or None,
'gpu_memory_total_mb': parse_number(parts[1]),
'gpu_memory_used_mb': parse_number(parts[2]),
'gpu_util_percent': parse_number(parts[3]),
}
def get_status(self) -> dict:
if psutil is None:
return {
'cpu_percent': 0.0,
'memory_percent': 0.0,
'disk_percent': 0.0,
'disk_used_gb': 0.0,
'disk_total_gb': 0.0,
'network_upload_bps': 0.0,
'network_download_bps': 0.0,
'system_name': platform.system(),
'system_version': platform.version(),
'hostname': socket.gethostname(),
'uptime_seconds': 0.0,
'gpu_name': None,
'gpu_memory_total_mb': None,
'gpu_memory_used_mb': None,
'gpu_util_percent': None,
'timestamp': datetime.now(UTC).isoformat(),
}
cpu_percent = psutil.cpu_percent(interval=None)
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
upload_bps, download_bps = self._get_network_rates()
gpu_status = self._get_gpu_status()
boot_time = psutil.boot_time()
now_ts = datetime.now(UTC).timestamp()
return {
'cpu_percent': round(cpu_percent, 1),
'memory_percent': round(memory.percent, 1),
'disk_percent': round(disk.percent, 1),
'disk_used_gb': round(disk.used / (1024 ** 3), 1),
'disk_total_gb': round(disk.total / (1024 ** 3), 1),
'network_upload_bps': upload_bps,
'network_download_bps': download_bps,
'system_name': platform.system(),
'system_version': platform.version(),
'hostname': socket.gethostname(),
'uptime_seconds': round(max(now_ts - boot_time, 0.0), 1),
**gpu_status,
'timestamp': datetime.now(UTC).isoformat(),
}