refactor(agents): centralize tool display definitions

This commit is contained in:
Peter Steinberger
2026-03-02 12:13:25 +00:00
parent d977af5853
commit d85d3c88d5
6 changed files with 310 additions and 576 deletions

View File

@@ -1,236 +0,0 @@
{
"version": 1,
"fallback": {
"icon": "puzzle",
"detailKeys": [
"command",
"path",
"url",
"targetUrl",
"targetId",
"ref",
"element",
"node",
"nodeId",
"id",
"requestId",
"to",
"channelId",
"guildId",
"userId",
"name",
"query",
"pattern",
"messageId"
]
},
"tools": {
"bash": {
"icon": "wrench",
"title": "Bash",
"detailKeys": ["command"]
},
"process": {
"icon": "wrench",
"title": "Process",
"detailKeys": ["sessionId"]
},
"read": {
"icon": "fileText",
"title": "Read",
"detailKeys": ["path"]
},
"write": {
"icon": "edit",
"title": "Write",
"detailKeys": ["path"]
},
"edit": {
"icon": "penLine",
"title": "Edit",
"detailKeys": ["path"]
},
"attach": {
"icon": "paperclip",
"title": "Attach",
"detailKeys": ["path", "url", "fileName"]
},
"browser": {
"icon": "globe",
"title": "Browser",
"actions": {
"status": { "label": "status" },
"start": { "label": "start" },
"stop": { "label": "stop" },
"tabs": { "label": "tabs" },
"open": { "label": "open", "detailKeys": ["targetUrl"] },
"focus": { "label": "focus", "detailKeys": ["targetId"] },
"close": { "label": "close", "detailKeys": ["targetId"] },
"snapshot": {
"label": "snapshot",
"detailKeys": ["targetUrl", "targetId", "ref", "element", "format"]
},
"screenshot": {
"label": "screenshot",
"detailKeys": ["targetUrl", "targetId", "ref", "element"]
},
"navigate": {
"label": "navigate",
"detailKeys": ["targetUrl", "targetId"]
},
"console": { "label": "console", "detailKeys": ["level", "targetId"] },
"pdf": { "label": "pdf", "detailKeys": ["targetId"] },
"upload": {
"label": "upload",
"detailKeys": ["paths", "ref", "inputRef", "element", "targetId"]
},
"dialog": {
"label": "dialog",
"detailKeys": ["accept", "promptText", "targetId"]
},
"act": {
"label": "act",
"detailKeys": [
"request.kind",
"request.ref",
"request.selector",
"request.text",
"request.value"
]
}
}
},
"canvas": {
"icon": "image",
"title": "Canvas",
"actions": {
"present": { "label": "present", "detailKeys": ["target", "node", "nodeId"] },
"hide": { "label": "hide", "detailKeys": ["node", "nodeId"] },
"navigate": { "label": "navigate", "detailKeys": ["url", "node", "nodeId"] },
"eval": { "label": "eval", "detailKeys": ["javaScript", "node", "nodeId"] },
"snapshot": { "label": "snapshot", "detailKeys": ["format", "node", "nodeId"] },
"a2ui_push": { "label": "A2UI push", "detailKeys": ["jsonlPath", "node", "nodeId"] },
"a2ui_reset": { "label": "A2UI reset", "detailKeys": ["node", "nodeId"] }
}
},
"nodes": {
"icon": "smartphone",
"title": "Nodes",
"actions": {
"status": { "label": "status" },
"describe": { "label": "describe", "detailKeys": ["node", "nodeId"] },
"pending": { "label": "pending" },
"approve": { "label": "approve", "detailKeys": ["requestId"] },
"reject": { "label": "reject", "detailKeys": ["requestId"] },
"notify": { "label": "notify", "detailKeys": ["node", "nodeId", "title", "body"] },
"camera_snap": {
"label": "camera snap",
"detailKeys": ["node", "nodeId", "facing", "deviceId"]
},
"camera_list": { "label": "camera list", "detailKeys": ["node", "nodeId"] },
"camera_clip": {
"label": "camera clip",
"detailKeys": ["node", "nodeId", "facing", "duration", "durationMs"]
},
"screen_record": {
"label": "screen record",
"detailKeys": ["node", "nodeId", "duration", "durationMs", "fps", "screenIndex"]
}
}
},
"cron": {
"icon": "loader",
"title": "Cron",
"actions": {
"status": { "label": "status" },
"list": { "label": "list" },
"add": {
"label": "add",
"detailKeys": ["job.name", "job.id", "job.schedule", "job.cron"]
},
"update": { "label": "update", "detailKeys": ["id"] },
"remove": { "label": "remove", "detailKeys": ["id"] },
"run": { "label": "run", "detailKeys": ["id"] },
"runs": { "label": "runs", "detailKeys": ["id"] },
"wake": { "label": "wake", "detailKeys": ["text", "mode"] }
}
},
"gateway": {
"icon": "plug",
"title": "Gateway",
"actions": {
"restart": { "label": "restart", "detailKeys": ["reason", "delayMs"] },
"config.get": { "label": "config get" },
"config.schema": { "label": "config schema" },
"config.apply": {
"label": "config apply",
"detailKeys": ["restartDelayMs"]
},
"update.run": {
"label": "update run",
"detailKeys": ["restartDelayMs"]
}
}
},
"whatsapp_login": {
"icon": "circle",
"title": "WhatsApp Login",
"actions": {
"start": { "label": "start" },
"wait": { "label": "wait" }
}
},
"discord": {
"icon": "messageSquare",
"title": "Discord",
"actions": {
"react": { "label": "react", "detailKeys": ["channelId", "messageId", "emoji"] },
"reactions": { "label": "reactions", "detailKeys": ["channelId", "messageId"] },
"sticker": { "label": "sticker", "detailKeys": ["to", "stickerIds"] },
"poll": { "label": "poll", "detailKeys": ["question", "to"] },
"permissions": { "label": "permissions", "detailKeys": ["channelId"] },
"readMessages": { "label": "read messages", "detailKeys": ["channelId", "limit"] },
"sendMessage": { "label": "send", "detailKeys": ["to", "content"] },
"editMessage": { "label": "edit", "detailKeys": ["channelId", "messageId"] },
"deleteMessage": { "label": "delete", "detailKeys": ["channelId", "messageId"] },
"threadCreate": { "label": "thread create", "detailKeys": ["channelId", "name"] },
"threadList": { "label": "thread list", "detailKeys": ["guildId", "channelId"] },
"threadReply": { "label": "thread reply", "detailKeys": ["channelId", "content"] },
"pinMessage": { "label": "pin", "detailKeys": ["channelId", "messageId"] },
"unpinMessage": { "label": "unpin", "detailKeys": ["channelId", "messageId"] },
"listPins": { "label": "list pins", "detailKeys": ["channelId"] },
"searchMessages": { "label": "search", "detailKeys": ["guildId", "content"] },
"memberInfo": { "label": "member", "detailKeys": ["guildId", "userId"] },
"roleInfo": { "label": "roles", "detailKeys": ["guildId"] },
"emojiList": { "label": "emoji list", "detailKeys": ["guildId"] },
"roleAdd": { "label": "role add", "detailKeys": ["guildId", "userId", "roleId"] },
"roleRemove": { "label": "role remove", "detailKeys": ["guildId", "userId", "roleId"] },
"channelInfo": { "label": "channel", "detailKeys": ["channelId"] },
"channelList": { "label": "channels", "detailKeys": ["guildId"] },
"voiceStatus": { "label": "voice", "detailKeys": ["guildId", "userId"] },
"eventList": { "label": "events", "detailKeys": ["guildId"] },
"eventCreate": { "label": "event create", "detailKeys": ["guildId", "name"] },
"timeout": { "label": "timeout", "detailKeys": ["guildId", "userId"] },
"kick": { "label": "kick", "detailKeys": ["guildId", "userId"] },
"ban": { "label": "ban", "detailKeys": ["guildId", "userId"] }
}
},
"slack": {
"icon": "messageSquare",
"title": "Slack",
"actions": {
"react": { "label": "react", "detailKeys": ["channelId", "messageId", "emoji"] },
"reactions": { "label": "reactions", "detailKeys": ["channelId", "messageId"] },
"sendMessage": { "label": "send", "detailKeys": ["to", "content"] },
"editMessage": { "label": "edit", "detailKeys": ["channelId", "messageId"] },
"deleteMessage": { "label": "delete", "detailKeys": ["channelId", "messageId"] },
"readMessages": { "label": "read messages", "detailKeys": ["channelId", "limit"] },
"pinMessage": { "label": "pin", "detailKeys": ["channelId", "messageId"] },
"unpinMessage": { "label": "unpin", "detailKeys": ["channelId", "messageId"] },
"listPins": { "label": "list pins", "detailKeys": ["channelId"] },
"memberInfo": { "label": "member", "detailKeys": ["userId"] },
"emojiList": { "label": "emoji list" }
}
}
}
}

View File

@@ -1,3 +1,4 @@
import SHARED_TOOL_DISPLAY_JSON from "../../../apps/shared/OpenClawKit/Sources/OpenClawKit/Resources/tool-display.json" with { type: "json" };
import {
defaultTitle,
formatToolDetailText,
@@ -7,16 +8,19 @@ import {
type ToolDisplaySpec as ToolDisplaySpecBase,
} from "../../../src/agents/tool-display-common.js";
import type { IconName } from "./icons.ts";
import rawConfig from "./tool-display.json" with { type: "json" };
type ToolDisplaySpec = ToolDisplaySpecBase & {
icon?: string;
};
type ToolDisplayConfig = {
type SharedToolDisplaySpec = ToolDisplaySpecBase & {
emoji?: string;
};
type SharedToolDisplayConfig = {
version?: number;
fallback?: ToolDisplaySpec;
tools?: Record<string, ToolDisplaySpec>;
fallback?: SharedToolDisplaySpec;
tools?: Record<string, SharedToolDisplaySpec>;
};
export type ToolDisplay = {
@@ -28,9 +32,67 @@ export type ToolDisplay = {
detail?: string;
};
const TOOL_DISPLAY_CONFIG = rawConfig as ToolDisplayConfig;
const FALLBACK = TOOL_DISPLAY_CONFIG.fallback ?? { icon: "puzzle" };
const TOOL_MAP = TOOL_DISPLAY_CONFIG.tools ?? {};
const EMOJI_ICON_MAP: Record<string, IconName> = {
"🧩": "puzzle",
"🛠️": "wrench",
"🧰": "wrench",
"📖": "fileText",
"✍️": "edit",
"📝": "penLine",
"📎": "paperclip",
"🌐": "globe",
"📺": "monitor",
"🧾": "fileText",
"🔐": "settings",
"💻": "monitor",
"🔌": "plug",
"💬": "messageSquare",
};
const SLACK_SPEC: ToolDisplaySpec = {
icon: "messageSquare",
title: "Slack",
actions: {
react: { label: "react", detailKeys: ["channelId", "messageId", "emoji"] },
reactions: { label: "reactions", detailKeys: ["channelId", "messageId"] },
sendMessage: { label: "send", detailKeys: ["to", "content"] },
editMessage: { label: "edit", detailKeys: ["channelId", "messageId"] },
deleteMessage: { label: "delete", detailKeys: ["channelId", "messageId"] },
readMessages: { label: "read messages", detailKeys: ["channelId", "limit"] },
pinMessage: { label: "pin", detailKeys: ["channelId", "messageId"] },
unpinMessage: { label: "unpin", detailKeys: ["channelId", "messageId"] },
listPins: { label: "list pins", detailKeys: ["channelId"] },
memberInfo: { label: "member", detailKeys: ["userId"] },
emojiList: { label: "emoji list" },
},
};
function iconForEmoji(emoji?: string): IconName {
if (!emoji) {
return "puzzle";
}
return EMOJI_ICON_MAP[emoji] ?? "puzzle";
}
function convertSpec(spec?: SharedToolDisplaySpec): ToolDisplaySpec {
return {
icon: iconForEmoji(spec?.emoji),
title: spec?.title,
label: spec?.label,
detailKeys: spec?.detailKeys,
actions: spec?.actions,
};
}
const SHARED_TOOL_DISPLAY_CONFIG = SHARED_TOOL_DISPLAY_JSON as SharedToolDisplayConfig;
const FALLBACK = convertSpec(SHARED_TOOL_DISPLAY_CONFIG.fallback ?? { emoji: "🧩" });
const TOOL_MAP: Record<string, ToolDisplaySpec> = Object.fromEntries(
Object.entries(SHARED_TOOL_DISPLAY_CONFIG.tools ?? {}).map(([key, spec]) => [
key,
convertSpec(spec),
]),
);
TOOL_MAP.slack = SLACK_SPEC;
function shortenHomeInString(input: string): string {
if (!input) {