From 14ed887ce3796c1eb44479bd26616fc161480851 Mon Sep 17 00:00:00 2001 From: zhi Date: Fri, 20 Mar 2026 08:12:58 +0000 Subject: [PATCH] =?UTF-8?q?refactor(telemetry):=20read=20agents=20via=20[?= =?UTF-8?q?=20=20=20{=20=20=20=20=20"id":=20"main",=20=20=20=20=20"identit?= =?UTF-8?q?yName":=20"=E9=9C=93=E5=85=89=20(Neon)",=20=20=20=20=20"identit?= =?UTF-8?q?yEmoji":=20"=E2=9C=A8",=20=20=20=20=20"identitySource":=20"iden?= =?UTF-8?q?tity",=20=20=20=20=20"workspace":=20"/root/.openclaw/workspace"?= =?UTF-8?q?,=20=20=20=20=20"agentDir":=20"/root/.openclaw/agents/main/agen?= =?UTF-8?q?t",=20=20=20=20=20"model":=20"minimax-portal/MiniMax-M2.5",=20?= =?UTF-8?q?=20=20=20=20"bindings":=201,=20=20=20=20=20"isDefault":=20true,?= =?UTF-8?q?=20=20=20=20=20"routes":=20[=20=20=20=20=20=20=20"default=20(no?= =?UTF-8?q?=20explicit=20rules)"=20=20=20=20=20]=20=20=20},=20=20=20{=20?= =?UTF-8?q?=20=20=20=20"id":=20"developer",=20=20=20=20=20"name":=20"devel?= =?UTF-8?q?oper",=20=20=20=20=20"identityName":=20"=E5=B0=8F=E6=99=BA=20(Z?= =?UTF-8?q?hi)",=20=20=20=20=20"identityEmoji":=20"=F0=9F=91=8B",=20=20=20?= =?UTF-8?q?=20=20"identitySource":=20"identity",=20=20=20=20=20"workspace"?= =?UTF-8?q?:=20"/root/.openclaw/workspace/workspace-developer",=20=20=20?= =?UTF-8?q?=20=20"agentDir":=20"/root/.openclaw/agents/developer/agent",?= =?UTF-8?q?=20=20=20=20=20"model":=20"anthropic/claude-opus-4-6",=20=20=20?= =?UTF-8?q?=20=20"bindings":=201,=20=20=20=20=20"isDefault":=20false=20=20?= =?UTF-8?q?=20},=20=20=20{=20=20=20=20=20"id":=20"dispatcher",=20=20=20=20?= =?UTF-8?q?=20"name":=20"dispatcher",=20=20=20=20=20"workspace":=20"/root/?= =?UTF-8?q?.openclaw/workspace/workspace-dispatcher",=20=20=20=20=20"agent?= =?UTF-8?q?Dir":=20"/root/.openclaw/agents/dispatcher/agent",=20=20=20=20?= =?UTF-8?q?=20"model":=20"minimax-portal/MiniMax-M2.5",=20=20=20=20=20"bin?= =?UTF-8?q?dings":=200,=20=20=20=20=20"isDefault":=20false=20=20=20},=20?= =?UTF-8?q?=20=20{=20=20=20=20=20"id":=20"operator",=20=20=20=20=20"name":?= =?UTF-8?q?=20"operator",=20=20=20=20=20"identityName":=20"=E6=99=A8?= =?UTF-8?q?=E6=9B=A6=20(Orion)",=20=20=20=20=20"identityEmoji":=20"?= =?UTF-8?q?=E2=9C=A8",=20=20=20=20=20"identitySource":=20"identity",=20=20?= =?UTF-8?q?=20=20=20"workspace":=20"/root/.openclaw/workspace/workspace-op?= =?UTF-8?q?erator",=20=20=20=20=20"agentDir":=20"/root/.openclaw/agents/op?= =?UTF-8?q?erator/agent",=20=20=20=20=20"model":=20"openai-codex/gpt-5.2-c?= =?UTF-8?q?odex",=20=20=20=20=20"bindings":=201,=20=20=20=20=20"isDefault"?= =?UTF-8?q?:=20false=20=20=20},=20=20=20{=20=20=20=20=20"id":=20"manager",?= =?UTF-8?q?=20=20=20=20=20"name":=20"manager",=20=20=20=20=20"identityName?= =?UTF-8?q?":=20"=E6=8C=87=E5=8D=97(Nav)",=20=20=20=20=20"identityEmoji":?= =?UTF-8?q?=20"=F0=9F=A7=AD",=20=20=20=20=20"identitySource":=20"identity"?= =?UTF-8?q?,=20=20=20=20=20"workspace":=20"/root/.openclaw/workspace/works?= =?UTF-8?q?pace-manager",=20=20=20=20=20"agentDir":=20"/root/.openclaw/age?= =?UTF-8?q?nts/manager/agent",=20=20=20=20=20"model":=20"openai-codex/gpt-?= =?UTF-8?q?5.2-codex",=20=20=20=20=20"bindings":=201,=20=20=20=20=20"isDef?= =?UTF-8?q?ault":=20false=20=20=20},=20=20=20{=20=20=20=20=20"id":=20"ment?= =?UTF-8?q?or",=20=20=20=20=20"name":=20"mentor",=20=20=20=20=20"identityN?= =?UTF-8?q?ame":=20"=E9=9C=96=20(Lyn)",=20=20=20=20=20"identityEmoji":=20"?= =?UTF-8?q?=F0=9F=AA=B6",=20=20=20=20=20"identitySource":=20"identity",=20?= =?UTF-8?q?=20=20=20=20"workspace":=20"/root/.openclaw/workspace/workspace?= =?UTF-8?q?-mentor",=20=20=20=20=20"agentDir":=20"/root/.openclaw/agents/m?= =?UTF-8?q?entor/agent",=20=20=20=20=20"model":=20"minimax-portal/MiniMax-?= =?UTF-8?q?M2.1",=20=20=20=20=20"bindings":=201,=20=20=20=20=20"isDefault"?= =?UTF-8?q?:=20false=20=20=20},=20=20=20{=20=20=20=20=20"id":=20"recruiter?= =?UTF-8?q?",=20=20=20=20=20"name":=20"recruiter",=20=20=20=20=20"identity?= =?UTF-8?q?Name":=20"=E6=B2=90=E5=B7=9D(Evan)",=20=20=20=20=20"identityEmo?= =?UTF-8?q?ji":=20"=F0=9F=A7=A9",=20=20=20=20=20"identitySource":=20"ident?= =?UTF-8?q?ity",=20=20=20=20=20"workspace":=20"/root/.openclaw/workspace/w?= =?UTF-8?q?orkspace-recruiter",=20=20=20=20=20"agentDir":=20"/root/.opencl?= =?UTF-8?q?aw/agents/recruiter/agent",=20=20=20=20=20"model":=20"minimax-p?= =?UTF-8?q?ortal/MiniMax-M2.5",=20=20=20=20=20"bindings":=200,=20=20=20=20?= =?UTF-8?q?=20"isDefault":=20false=20=20=20},=20=20=20{=20=20=20=20=20"id"?= =?UTF-8?q?:=20"administrative-secretary",=20=20=20=20=20"name":=20"admini?= =?UTF-8?q?strative-secretary",=20=20=20=20=20"identityName":=20"=E6=98=A0?= =?UTF-8?q?=E7=A7=98(Mirror)",=20=20=20=20=20"identityEmoji":=20"?= =?UTF-8?q?=F0=9F=AA=9E",=20=20=20=20=20"identitySource":=20"identity",=20?= =?UTF-8?q?=20=20=20=20"workspace":=20"/root/.openclaw/workspace/workspace?= =?UTF-8?q?-administrative-secretary",=20=20=20=20=20"agentDir":=20"/root/?= =?UTF-8?q?.openclaw/agents/administrative-secretary/agent",=20=20=20=20?= =?UTF-8?q?=20"model":=20"minimax-portal/MiniMax-M2.5",=20=20=20=20=20"bin?= =?UTF-8?q?dings":=201,=20=20=20=20=20"isDefault":=20false=20=20=20},=20?= =?UTF-8?q?=20=20{=20=20=20=20=20"id":=20"agent-resource-director",=20=20?= =?UTF-8?q?=20=20=20"name":=20"agent-resource-director",=20=20=20=20=20"id?= =?UTF-8?q?entityName":=20"=E5=BD=B1=E7=BB=87(Sherlock)",=20=20=20=20=20"i?= =?UTF-8?q?dentityEmoji":=20"=F0=9F=95=B8=EF=B8=8F",=20=20=20=20=20"identi?= =?UTF-8?q?tySource":=20"identity",=20=20=20=20=20"workspace":=20"/root/.o?= =?UTF-8?q?penclaw/workspace/workspace-agent-resource-director",=20=20=20?= =?UTF-8?q?=20=20"agentDir":=20"/root/.openclaw/agents/agent-resource-dire?= =?UTF-8?q?ctor/agent",=20=20=20=20=20"model":=20"kimi-coding/kimi-k2-thin?= =?UTF-8?q?king",=20=20=20=20=20"bindings":=201,=20=20=20=20=20"isDefault"?= =?UTF-8?q?:=20false=20=20=20}=20]=20[plugins]=20memory-lancedb-pro@1.1.0-?= =?UTF-8?q?beta.6:=20plugin=20registered=20(db:=20/root/.openclaw/memory/l?= =?UTF-8?q?ancedb-pro,=20model:=20jina-embeddings-v5-text-small)=20[plugin?= =?UTF-8?q?s]=20memory-lancedb-pro:=20diagnostic=20build=20tag=20loaded=20?= =?UTF-8?q?(memory-lancedb-pro-diag-20260308-0058)=20[plugins]=20self-impr?= =?UTF-8?q?ovement:=20integrated=20hooks=20registered=20(agent:bootstrap,?= =?UTF-8?q?=20command:new,=20command:reset)=20[plugins]=20session-strategy?= =?UTF-8?q?:=20using=20systemSessionMemory=20(plugin=20memory-reflection?= =?UTF-8?q?=20hooks=20disabled)=20[plugins]=20PaddedCell=20plugin=20initia?= =?UTF-8?q?lizing...=20[plugins]=20PaddedCell=20plugin=20initialized=20[pl?= =?UTF-8?q?ugins]=20dirigent:=20pluginDir=20resolved=20from=20import.meta.?= =?UTF-8?q?url:=20/root/.openclaw/plugins/dirigent=20[plugins]=20hook=20ru?= =?UTF-8?q?nner=20initialized=20with=203=20registered=20hooks=20[plugins]?= =?UTF-8?q?=20hook=20runner=20initialized=20with=203=20registered=20hooks?= =?UTF-8?q?=20[plugins]=20hook=20runner=20initialized=20with=203=20registe?= =?UTF-8?q?red=20hooks=20[plugins]=20hook=20runner=20initialized=20with=20?= =?UTF-8?q?3=20registered=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Prefer OpenClaw CLI as source of truth for agent list - Parse JSON prefix defensively when plugin logs trail output - Keep file/directory discovery only as fallback --- server/telemetry.mjs | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/server/telemetry.mjs b/server/telemetry.mjs index be3a14b..fcb6e6d 100644 --- a/server/telemetry.mjs +++ b/server/telemetry.mjs @@ -185,8 +185,59 @@ async function collectOpenclawStatus() { /** * Get list of OpenClaw agents from local state */ +function extractJsonPrefix(text) { + const trimmed = text.trim(); + if (!trimmed) return null; + + const startsWith = trimmed[0]; + if (startsWith !== '[' && startsWith !== '{') return null; + + let depth = 0; + let inString = false; + let escape = false; + for (let i = 0; i < trimmed.length; i += 1) { + const ch = trimmed[i]; + if (escape) { + escape = false; + continue; + } + if (ch === '\\') { + escape = true; + continue; + } + if (ch === '"') { + inString = !inString; + continue; + } + if (inString) continue; + if (ch === '[' || ch === '{') depth += 1; + if (ch === ']' || ch === '}') depth -= 1; + if (depth === 0) { + return trimmed.slice(0, i + 1); + } + } + return null; +} + async function getOpenclawAgents() { try { + try { + const { stdout } = await execAsync('openclaw agents list --json 2>/dev/null'); + const jsonPrefix = extractJsonPrefix(stdout); + if (jsonPrefix) { + const agents = JSON.parse(jsonPrefix); + if (Array.isArray(agents)) { + return agents.map((agent) => ({ + id: agent.id, + name: agent.name || agent.id, + status: agent.isDefault ? 'default' : 'configured', + })); + } + } + } catch (err) { + log.debug('Failed to get agents from `openclaw agents list --json`:', err.message); + } + const agentConfigPath = `${CONFIG.openclawPath}/agents.json`; try { await access(agentConfigPath, constants.R_OK);