mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-16 07:20:59 +00:00
feat: show connector error details for Plugin and Box runtime status
Record Box connector error in BoxService and expose it as 'connector_error' in GET /api/v1/box/status when unavailable. Display error messages in the dashboard System Status popover for both Plugin Runtime (plugin_connector_error) and Box Runtime (connector_error) when they are disconnected.
This commit is contained in:
@@ -66,6 +66,7 @@ class BoxService:
|
|||||||
self._recent_errors: collections.deque[dict] = collections.deque(maxlen=_MAX_RECENT_ERRORS)
|
self._recent_errors: collections.deque[dict] = collections.deque(maxlen=_MAX_RECENT_ERRORS)
|
||||||
self._shutdown_task = None
|
self._shutdown_task = None
|
||||||
self._available = False
|
self._available = False
|
||||||
|
self._connector_error: str = ''
|
||||||
|
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
self._ensure_default_host_workspace()
|
self._ensure_default_host_workspace()
|
||||||
@@ -75,6 +76,7 @@ class BoxService:
|
|||||||
else:
|
else:
|
||||||
await self.client.initialize()
|
await self.client.initialize()
|
||||||
self._available = True
|
self._available = True
|
||||||
|
self._connector_error = ''
|
||||||
self.ap.logger.info(
|
self.ap.logger.info(
|
||||||
f'LangBot Box runtime initialized: profile={self.profile.name} '
|
f'LangBot Box runtime initialized: profile={self.profile.name} '
|
||||||
f'default_workspace={self.default_host_workspace or "(none)"}'
|
f'default_workspace={self.default_host_workspace or "(none)"}'
|
||||||
@@ -82,17 +84,21 @@ class BoxService:
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self.ap.logger.warning(f'LangBot Box runtime unavailable, sandbox features disabled: {exc}')
|
self.ap.logger.warning(f'LangBot Box runtime unavailable, sandbox features disabled: {exc}')
|
||||||
self._available = False
|
self._available = False
|
||||||
|
self._connector_error = str(exc)
|
||||||
|
|
||||||
async def _on_runtime_disconnect(self, connector: BoxRuntimeConnector) -> None:
|
async def _on_runtime_disconnect(self, connector: BoxRuntimeConnector) -> None:
|
||||||
"""Called by the connector when the Box runtime connection drops."""
|
"""Called by the connector when the Box runtime connection drops."""
|
||||||
self._available = False
|
self._available = False
|
||||||
|
self._connector_error = 'Disconnected from Box runtime'
|
||||||
self.ap.logger.warning('Box runtime disconnected, sandbox features temporarily disabled. Reconnecting in 3s...')
|
self.ap.logger.warning('Box runtime disconnected, sandbox features temporarily disabled. Reconnecting in 3s...')
|
||||||
await asyncio.sleep(3)
|
await asyncio.sleep(3)
|
||||||
try:
|
try:
|
||||||
await connector.initialize()
|
await connector.initialize()
|
||||||
self._available = True
|
self._available = True
|
||||||
|
self._connector_error = ''
|
||||||
self.ap.logger.info('Box runtime reconnected, sandbox features restored.')
|
self.ap.logger.info('Box runtime reconnected, sandbox features restored.')
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
self._connector_error = str(exc)
|
||||||
self.ap.logger.warning(f'Box runtime reconnection failed: {exc}. Will retry on next heartbeat disconnect.')
|
self.ap.logger.warning(f'Box runtime reconnection failed: {exc}. Will retry on next heartbeat disconnect.')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -573,6 +579,7 @@ class BoxService:
|
|||||||
'available': False,
|
'available': False,
|
||||||
'profile': self.profile.name,
|
'profile': self.profile.name,
|
||||||
'recent_error_count': len(self._recent_errors),
|
'recent_error_count': len(self._recent_errors),
|
||||||
|
'connector_error': self._connector_error,
|
||||||
}
|
}
|
||||||
runtime_status = await self.client.get_status()
|
runtime_status = await self.client.get_status()
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -131,6 +131,15 @@ export default function SystemStatusCard() {
|
|||||||
{t('monitoring.pluginDisabled')}
|
{t('monitoring.pluginDisabled')}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
{pluginStatus &&
|
||||||
|
!pluginOk &&
|
||||||
|
pluginStatus.is_enable &&
|
||||||
|
pluginStatus.plugin_connector_error &&
|
||||||
|
pluginStatus.plugin_connector_error !== 'ok' && (
|
||||||
|
<p className="text-red-400 break-all">
|
||||||
|
{pluginStatus.plugin_connector_error}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -157,6 +166,11 @@ export default function SystemStatusCard() {
|
|||||||
: t('monitoring.disconnected')}
|
: t('monitoring.disconnected')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{boxStatus && !boxOk && boxStatus.connector_error && (
|
||||||
|
<p className="text-red-400 break-all">
|
||||||
|
{boxStatus.connector_error}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
{boxStatus && (
|
{boxStatus && (
|
||||||
<div className="text-muted-foreground space-y-0.5">
|
<div className="text-muted-foreground space-y-0.5">
|
||||||
{boxStatus.backend && (
|
{boxStatus.backend && (
|
||||||
|
|||||||
@@ -355,6 +355,7 @@ export interface ApiRespBoxStatus {
|
|||||||
available: boolean;
|
available: boolean;
|
||||||
profile: string;
|
profile: string;
|
||||||
recent_error_count: number;
|
recent_error_count: number;
|
||||||
|
connector_error?: string;
|
||||||
backend?: {
|
backend?: {
|
||||||
name: string;
|
name: string;
|
||||||
available: boolean;
|
available: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user