Compare commits

...

3 Commits

Author SHA1 Message Date
operator
248adfaafd fix: use runtime API for version and agent list instead of subprocess
Use api.runtime.version for openclaw version and
api.runtime.config.loadConfig() for agent list. Eliminates the
periodic openclaw agents list subprocess that caused high CPU usage.
2026-04-16 15:53:20 +00:00
operator
e4ac7b7af3 fix: disable periodic openclaw agents list subprocess
Spawning a full openclaw CLI process every 30s to list agents is too
heavy — each invocation loads all plugins (~16s) and hangs until killed.
Return empty array for now until a lighter mechanism is available.
2026-04-16 15:26:55 +00:00
operator
2088cd12b4 fix: use OPENCLAW_SERVICE_VERSION for real version and increase agent list timeout
api.version returns plugin API version (0.2.0), not the openclaw release
version. Use OPENCLAW_SERVICE_VERSION env var set by the gateway instead.
Also increase listOpenClawAgents timeout from 15s to 30s since plugin
loading takes ~16s on T2.
2026-04-16 15:12:35 +00:00
2 changed files with 35 additions and 55 deletions

View File

@@ -1,8 +1,3 @@
import { execFile } from 'child_process';
import { promisify } from 'util';
const execFileAsync = promisify(execFile);
export interface OpenClawAgentInfo { export interface OpenClawAgentInfo {
name: string; name: string;
isDefault?: boolean; isDefault?: boolean;
@@ -14,70 +9,38 @@ export interface OpenClawAgentInfo {
routing?: string; routing?: string;
} }
export async function listOpenClawAgents(logger?: { debug?: (...args: any[]) => void; warn?: (...args: any[]) => void }): Promise<OpenClawAgentInfo[]> { export async function listOpenClawAgents(_logger?: { debug?: (...args: any[]) => void; warn?: (...args: any[]) => void }): Promise<OpenClawAgentInfo[]> {
try { return [];
const { stdout } = await execFileAsync('openclaw', ['agents', 'list'], {
timeout: 15000,
maxBuffer: 1024 * 1024,
});
return parseOpenClawAgents(stdout);
} catch (err) {
logger?.warn?.('Failed to run `openclaw agents list`', err);
return [];
}
} }
export function parseOpenClawAgents(text: string): OpenClawAgentInfo[] { export function parseOpenClawAgents(text: string): OpenClawAgentInfo[] {
const lines = text.split(/\r?\n/); const lines = text.split(/\r?\n/);
const out: OpenClawAgentInfo[] = []; const out: OpenClawAgentInfo[] = [];
let current: OpenClawAgentInfo | null = null; let current: OpenClawAgentInfo | null = null;
const push = () => { if (current) out.push(current); current = null; };
const push = () => {
if (current) out.push(current);
current = null;
};
for (const raw of lines) { for (const raw of lines) {
const line = raw.trimEnd(); const line = raw.trimEnd();
if (!line.trim() || line.startsWith('Agents:') || line.startsWith('Routing rules map') || line.startsWith('Channel status reflects')) continue; if (!line.trim() || line.startsWith("Agents:") || line.startsWith("Routing rules map") || line.startsWith("Channel status reflects")) continue;
if (line.startsWith('- ')) { if (line.startsWith("- ")) {
push(); push();
const m = line.match(/^-\s+(.+?)(?:\s+\((default)\))?$/); const m = line.match(/^-\s+(.+?)(?:\s+\((default)\))?$/);
current = { current = { name: m?.[1] || line.slice(2).trim(), isDefault: m?.[2] === "default" };
name: m?.[1] || line.slice(2).trim(),
isDefault: m?.[2] === 'default',
};
continue; continue;
} }
if (!current) continue; if (!current) continue;
const trimmed = line.trim(); const trimmed = line.trim();
const idx = trimmed.indexOf(':'); const idx = trimmed.indexOf(":");
if (idx === -1) continue; if (idx === -1) continue;
const key = trimmed.slice(0, idx).trim(); const key = trimmed.slice(0, idx).trim();
const value = trimmed.slice(idx + 1).trim(); const value = trimmed.slice(idx + 1).trim();
switch (key) { switch (key) {
case 'Identity': case "Identity": current.identity = value; break;
current.identity = value; case "Workspace": current.workspace = value; break;
break; case "Agent dir": current.agentDir = value; break;
case 'Workspace': case "Model": current.model = value; break;
current.workspace = value; case "Routing rules": { const n = Number(value); current.routingRules = Number.isFinite(n) ? n : undefined; break; }
break; case "Routing": current.routing = value; break;
case 'Agent dir': default: break;
current.agentDir = value;
break;
case 'Model':
current.model = value;
break;
case 'Routing rules': {
const n = Number(value);
current.routingRules = Number.isFinite(n) ? n : undefined;
break;
}
case 'Routing':
current.routing = value;
break;
default:
break;
} }
} }
push(); push();

View File

@@ -14,7 +14,7 @@
import { hostname, freemem, totalmem, uptime, loadavg, platform } from 'os'; import { hostname, freemem, totalmem, uptime, loadavg, platform } from 'os';
import { getPluginConfig } from './core/config'; import { getPluginConfig } from './core/config';
import { MonitorBridgeClient, type OpenClawMeta } from './core/monitor-bridge'; import { MonitorBridgeClient, type OpenClawMeta } from './core/monitor-bridge';
import { listOpenClawAgents } from './core/openclaw-agents'; import type { OpenClawAgentInfo } from './core/openclaw-agents';
import { registerGatewayStartHook } from './hooks/gateway-start'; import { registerGatewayStartHook } from './hooks/gateway-start';
import { registerGatewayStopHook } from './hooks/gateway-stop'; import { registerGatewayStopHook } from './hooks/gateway-stop';
import { import {
@@ -32,6 +32,12 @@ interface PluginAPI {
warn: (...args: any[]) => void; warn: (...args: any[]) => void;
}; };
version?: string; version?: string;
runtime?: {
version?: string;
config?: {
loadConfig?: () => any;
};
};
config?: Record<string, unknown>; config?: Record<string, unknown>;
pluginConfig?: Record<string, unknown>; pluginConfig?: Record<string, unknown>;
on: (event: string, handler: () => void) => void; on: (event: string, handler: () => void) => void;
@@ -96,7 +102,7 @@ export default {
avg15: load[2], avg15: load[2],
}, },
openclaw: { openclaw: {
version: api.version || 'unknown', version: api.runtime?.version || api.version || 'unknown',
pluginVersion: '0.3.1', // Bumped for PLG-CAL-004 pluginVersion: '0.3.1', // Bumped for PLG-CAL-004
}, },
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
@@ -118,10 +124,21 @@ export default {
const bridgeClient = getBridgeClient(); const bridgeClient = getBridgeClient();
if (!bridgeClient) return; if (!bridgeClient) return;
let agentNames: string[] = [];
try {
const cfg = api.runtime?.config?.loadConfig?.();
const agentsList = cfg?.agents?.list;
if (Array.isArray(agentsList)) {
agentNames = agentsList
.map((a: any) => typeof a === 'string' ? a : a?.name)
.filter(Boolean);
}
} catch { /* non-fatal */ }
const meta: OpenClawMeta = { const meta: OpenClawMeta = {
version: api.version || 'unknown', version: api.runtime?.version || api.version || 'unknown',
plugin_version: '0.3.1', plugin_version: '0.3.1',
agents: await listOpenClawAgents(logger), agents: agentNames.map(name => ({ name })),
}; };
const ok = await bridgeClient.pushOpenClawMeta(meta); const ok = await bridgeClient.pushOpenClawMeta(meta);