# Auto generated by LangBot Plugin SDK. # Please refer to https://langbot.app/docs/en/plugin/dev/tutor.html for more details. from __future__ import annotations from typing import Any, AsyncGenerator from langbot_plugin.api.definition.components.command.command import Command, Subcommand from langbot_plugin.api.entities.builtin.command.context import ExecuteContext, CommandReturn import asyncio import os import psutil def _collect_status() -> str: """Read host/process statistics (worker-scoped, never tenant data). ``cpu_percent(interval=None)`` is non-blocking: it reports the delta since the previous call instead of sleeping for the sample window. All readings describe the shared plugin worker's host and process, not the calling tenant's machine. The caller runs this off the event loop. """ core_mem = psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 sysmem_info = psutil.virtual_memory() cpu_times = psutil.cpu_times() disk_info = psutil.disk_usage('/') cpu_freq = psutil.cpu_freq() cpu_percent = psutil.cpu_percent(interval=None) return f"""====系统状态==== 进程内存占用: {core_mem:.2f}MB 总内存: {sysmem_info.total / 1024 / 1024:.2f}MB 已用内存: {sysmem_info.used / 1024 / 1024:.2f}MB 空闲内存: {sysmem_info.free / 1024 / 1024:.2f}MB 内存使用率: {sysmem_info.percent:.2f}% 用户态CPU时间: {cpu_times.user:.2f}秒 系统态CPU时间: {cpu_times.system:.2f}秒 空闲CPU时间: {cpu_times.idle:.2f}秒 CPU使用率: {cpu_percent:.2f}% CPU逻辑核心数: {psutil.cpu_count()} CPU物理核心数: {psutil.cpu_count(logical=False)} CPU当前频率: {cpu_freq.current:.2f}MHz 总磁盘空间: {disk_info.total / 1024 / 1024 / 1024:.2f}GB 已用磁盘空间: {disk_info.used / 1024 / 1024 / 1024:.2f}GB 空闲磁盘空间: {disk_info.free / 1024 / 1024 / 1024:.2f}GB 磁盘使用率: {disk_info.percent:.2f}% ============""".strip() class SysStat(Command): def __init__(self): super().__init__() @self.subcommand( name="", help="View system status including CPU, memory, and disk usage", usage="sysstat", aliases=["sys"], ) async def show_status(self, context: ExecuteContext) -> AsyncGenerator[CommandReturn, None]: """Show system status""" try: # Offload the syscall/CPU sampling so overlapping tenant # invocations are not stalled by this worker's collection. res = await asyncio.to_thread(_collect_status) yield CommandReturn( text=res, ) except Exception as e: yield CommandReturn( error=f"获取系统状态失败: {str(e)}", )