fix(tool-display): generate swift snapshot from core config

This commit is contained in:
Vincent Koc 2026-04-05 10:33:47 +01:00
parent e468da1040
commit 64cf52ca20
8 changed files with 1697 additions and 373 deletions

View file

@ -130,44 +130,7 @@ public enum ToolDisplayRegistry {
"messageId",
],
actions: nil),
tools: [
"bash": ToolDisplaySpec(
emoji: "🛠️",
title: "Bash",
label: nil,
detailKeys: ["command"],
actions: nil),
"read": ToolDisplaySpec(
emoji: "📖",
title: "Read",
label: nil,
detailKeys: ["path"],
actions: nil),
"write": ToolDisplaySpec(
emoji: "✍️",
title: "Write",
label: nil,
detailKeys: ["path"],
actions: nil),
"edit": ToolDisplaySpec(
emoji: "📝",
title: "Edit",
label: nil,
detailKeys: ["path"],
actions: nil),
"attach": ToolDisplaySpec(
emoji: "📎",
title: "Attach",
label: nil,
detailKeys: ["path", "url", "fileName"],
actions: nil),
"process": ToolDisplaySpec(
emoji: "🧰",
title: "Process",
label: nil,
detailKeys: ["sessionId"],
actions: nil),
])
tools: nil)
}
private static func titleFromName(_ name: String) -> String {

View file

@ -9,8 +9,8 @@ import Testing
}
@Test func resolvesKnownToolFromConfig() {
let summary = ToolDisplayRegistry.resolve(name: "bash", args: nil)
let summary = ToolDisplayRegistry.resolve(name: "exec", args: nil)
#expect(summary.emoji == "🛠️")
#expect(summary.title == "Bash")
#expect(summary.title == "Exec")
}
}

View file

@ -893,7 +893,7 @@
"canon:check:json": "node scripts/canon.mjs check --json",
"canon:enforce": "node scripts/canon.mjs enforce --json",
"canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh",
"check": "pnpm check:no-conflict-markers && pnpm check:host-env-policy:swift && pnpm tsgo && pnpm lint && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope",
"check": "pnpm check:no-conflict-markers && pnpm tool-display:check && pnpm check:host-env-policy:swift && pnpm tsgo && pnpm lint && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope",
"check:base-config-schema": "node --import tsx scripts/generate-base-config-schema.ts --check",
"check:bundled-channel-config-metadata": "node --import tsx scripts/generate-bundled-channel-config-metadata.ts --check",
"check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-i18n-glossary && pnpm docs:check-links",
@ -1067,6 +1067,8 @@
"test:ui": "pnpm lint:ui:no-raw-window-open && pnpm --dir ui test",
"test:voicecall:closedloop": "node scripts/test-voicecall-closedloop.mjs",
"test:watch": "vitest --config vitest.config.ts",
"tool-display:check": "node --import tsx scripts/tool-display.ts --check",
"tool-display:write": "node --import tsx scripts/tool-display.ts --write",
"ts-topology": "node --import tsx scripts/ts-topology.ts",
"tsgo": "node scripts/run-tsgo.mjs",
"tui": "node scripts/run-node.mjs tui",

93
scripts/tool-display.ts Normal file
View file

@ -0,0 +1,93 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
TOOL_DISPLAY_CONFIG,
serializeToolDisplayConfig,
} from "../src/agents/tool-display-config.js";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, "..");
const outputPath = path.join(
repoRoot,
"apps/shared/OpenClawKit/Sources/OpenClawKit/Resources/tool-display.json",
);
const toolSources = [
path.join(repoRoot, "src/agents/apply-patch.ts"),
path.join(repoRoot, "src/agents/bash-tools.exec.ts"),
path.join(repoRoot, "src/agents/bash-tools.process.ts"),
path.join(repoRoot, "src/auto-reply/reply/acp-projector.ts"),
];
const args = new Set(process.argv.slice(2));
const shouldCheck = args.has("--check");
const shouldWrite = args.has("--write");
if (!shouldCheck && !shouldWrite) {
console.error("Usage: node --import tsx scripts/tool-display.ts --check|--write");
process.exit(1);
}
const expected = serializeToolDisplayConfig();
ensureCoreToolCoverage();
if (shouldWrite) {
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, expected);
process.stdout.write(`wrote ${path.relative(repoRoot, outputPath)}\n`);
process.exit(0);
}
if (!fs.existsSync(path.dirname(outputPath))) {
process.stdout.write(
`skip tool-display snapshot check; missing ${path.relative(repoRoot, path.dirname(outputPath))}\n`,
);
process.exit(0);
}
if (!fs.existsSync(outputPath)) {
console.error(
`missing generated snapshot: ${path.relative(repoRoot, outputPath)}\nrun: pnpm tool-display:write`,
);
process.exit(1);
}
const actual = fs.readFileSync(outputPath, "utf8");
if (actual !== expected) {
console.error(
`tool-display snapshot is stale: ${path.relative(repoRoot, outputPath)}\nrun: pnpm tool-display:write`,
);
process.exit(1);
}
process.stdout.write("tool-display snapshot is up to date\n");
function ensureCoreToolCoverage() {
const toolNames = new Set<string>();
for (const sourcePath of toolSources) {
collectToolNamesFromFile(sourcePath, toolNames);
}
for (const entry of fs.readdirSync(path.join(repoRoot, "src/agents/tools"))) {
if (!entry.endsWith(".ts") || entry.endsWith(".test.ts")) {
continue;
}
collectToolNamesFromFile(path.join(repoRoot, "src/agents/tools", entry), toolNames);
}
const missing = [...toolNames].filter((name) => !TOOL_DISPLAY_CONFIG.tools[name]).toSorted();
if (missing.length > 0) {
console.error(
`tool-display metadata missing for runtime tools: ${missing.join(", ")}\nupdate: src/agents/tool-display-config.ts`,
);
process.exit(1);
}
}
function collectToolNamesFromFile(sourcePath: string, names: Set<string>) {
const source = fs.readFileSync(sourcePath, "utf8");
for (const match of source.matchAll(/\bname:\s*"([A-Za-z0-9_-]+)"/g)) {
const name = match[1]?.trim();
if (name) {
names.add(name);
}
}
}

View file

@ -0,0 +1,660 @@
import type { ToolDisplaySpec as ToolDisplaySpecBase } from "./tool-display-common.js";
export type ToolDisplaySpec = ToolDisplaySpecBase & {
emoji?: string;
};
export type ToolDisplayConfig = {
version: number;
fallback: ToolDisplaySpec;
tools: Record<string, ToolDisplaySpec>;
};
export const TOOL_DISPLAY_CONFIG: ToolDisplayConfig = {
version: 1,
fallback: {
emoji: "🧩",
detailKeys: [
"command",
"path",
"url",
"targetUrl",
"targetId",
"ref",
"element",
"node",
"nodeId",
"id",
"requestId",
"to",
"channelId",
"guildId",
"userId",
"name",
"query",
"pattern",
"messageId",
],
},
tools: {
bash: {
emoji: "🛠️",
title: "Bash",
detailKeys: ["command"],
},
process: {
emoji: "🧰",
title: "Process",
detailKeys: ["sessionId"],
},
read: {
emoji: "📖",
title: "Read",
detailKeys: ["path"],
},
write: {
emoji: "✍️",
title: "Write",
detailKeys: ["path"],
},
edit: {
emoji: "📝",
title: "Edit",
detailKeys: ["path"],
},
attach: {
emoji: "📎",
title: "Attach",
detailKeys: ["path", "url", "fileName"],
},
browser: {
emoji: "🌐",
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: {
emoji: "🖼️",
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: {
emoji: "📱",
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: {
emoji: "⏰",
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: {
emoji: "🔌",
title: "Gateway",
actions: {
restart: {
label: "restart",
detailKeys: ["reason", "delayMs"],
},
},
},
whatsapp_login: {
emoji: "🟢",
title: "WhatsApp Login",
actions: {
start: {
label: "start",
},
wait: {
label: "wait",
},
},
},
discord: {
emoji: "💬",
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"],
},
},
},
exec: {
emoji: "🛠️",
title: "Exec",
detailKeys: ["command"],
},
tool_call: {
emoji: "🧰",
title: "Tool Call",
detailKeys: [],
},
tool_call_update: {
emoji: "🧰",
title: "Tool Call",
detailKeys: [],
},
session_status: {
emoji: "📊",
title: "Session Status",
detailKeys: ["sessionKey", "model"],
},
sessions_list: {
emoji: "🗂️",
title: "Sessions",
detailKeys: ["kinds", "limit", "activeMinutes", "messageLimit"],
},
sessions_send: {
emoji: "📨",
title: "Session Send",
detailKeys: ["label", "sessionKey", "agentId", "timeoutSeconds"],
},
sessions_history: {
emoji: "🧾",
title: "Session History",
detailKeys: ["sessionKey", "limit", "includeTools"],
},
sessions_spawn: {
emoji: "🧑‍🔧",
title: "Sub-agent",
detailKeys: ["label", "task", "agentId", "model", "thinking", "runTimeoutSeconds", "cleanup"],
},
subagents: {
emoji: "🤖",
title: "Subagents",
actions: {
list: {
label: "list",
detailKeys: ["recentMinutes"],
},
kill: {
label: "kill",
detailKeys: ["target"],
},
steer: {
label: "steer",
detailKeys: ["target"],
},
},
},
agents_list: {
emoji: "🧭",
title: "Agents",
detailKeys: [],
},
memory_search: {
emoji: "🧠",
title: "Memory Search",
detailKeys: ["query"],
},
memory_get: {
emoji: "📓",
title: "Memory Get",
detailKeys: ["path", "from", "lines"],
},
web_search: {
emoji: "🔎",
title: "Web Search",
detailKeys: ["query", "count"],
},
web_fetch: {
emoji: "📄",
title: "Web Fetch",
detailKeys: ["url", "extractMode", "maxChars"],
},
code_execution: {
emoji: "🧮",
title: "Code Execution",
detailKeys: ["task"],
},
message: {
emoji: "✉️",
title: "Message",
actions: {
send: {
label: "send",
detailKeys: ["provider", "to", "media", "replyTo", "threadId"],
},
poll: {
label: "poll",
detailKeys: ["provider", "to", "pollQuestion"],
},
react: {
label: "react",
detailKeys: ["provider", "to", "messageId", "emoji", "remove"],
},
reactions: {
label: "reactions",
detailKeys: ["provider", "to", "messageId", "limit"],
},
read: {
label: "read",
detailKeys: ["provider", "to", "limit"],
},
edit: {
label: "edit",
detailKeys: ["provider", "to", "messageId"],
},
delete: {
label: "delete",
detailKeys: ["provider", "to", "messageId"],
},
pin: {
label: "pin",
detailKeys: ["provider", "to", "messageId"],
},
unpin: {
label: "unpin",
detailKeys: ["provider", "to", "messageId"],
},
"list-pins": {
label: "list pins",
detailKeys: ["provider", "to"],
},
permissions: {
label: "permissions",
detailKeys: ["provider", "channelId", "to"],
},
"thread-create": {
label: "thread create",
detailKeys: ["provider", "channelId", "threadName"],
},
"thread-list": {
label: "thread list",
detailKeys: ["provider", "guildId", "channelId"],
},
"thread-reply": {
label: "thread reply",
detailKeys: ["provider", "channelId", "messageId"],
},
search: {
label: "search",
detailKeys: ["provider", "guildId", "query"],
},
sticker: {
label: "sticker",
detailKeys: ["provider", "to", "stickerId"],
},
"member-info": {
label: "member",
detailKeys: ["provider", "guildId", "userId"],
},
"role-info": {
label: "roles",
detailKeys: ["provider", "guildId"],
},
"emoji-list": {
label: "emoji list",
detailKeys: ["provider", "guildId"],
},
"emoji-upload": {
label: "emoji upload",
detailKeys: ["provider", "guildId", "emojiName"],
},
"sticker-upload": {
label: "sticker upload",
detailKeys: ["provider", "guildId", "stickerName"],
},
"role-add": {
label: "role add",
detailKeys: ["provider", "guildId", "userId", "roleId"],
},
"role-remove": {
label: "role remove",
detailKeys: ["provider", "guildId", "userId", "roleId"],
},
"channel-info": {
label: "channel",
detailKeys: ["provider", "channelId"],
},
"channel-list": {
label: "channels",
detailKeys: ["provider", "guildId"],
},
"voice-status": {
label: "voice",
detailKeys: ["provider", "guildId", "userId"],
},
"event-list": {
label: "events",
detailKeys: ["provider", "guildId"],
},
"event-create": {
label: "event create",
detailKeys: ["provider", "guildId", "eventName"],
},
timeout: {
label: "timeout",
detailKeys: ["provider", "guildId", "userId"],
},
kick: {
label: "kick",
detailKeys: ["provider", "guildId", "userId"],
},
ban: {
label: "ban",
detailKeys: ["provider", "guildId", "userId"],
},
},
},
apply_patch: {
emoji: "🩹",
title: "Apply Patch",
detailKeys: [],
},
image: {
emoji: "🖼️",
title: "Image",
detailKeys: ["path", "paths", "url", "urls", "prompt", "model"],
},
image_generate: {
emoji: "🎨",
title: "Image Generation",
actions: {
generate: {
label: "generate",
detailKeys: ["prompt", "model", "count", "resolution", "aspectRatio"],
},
list: {
label: "list",
detailKeys: ["provider", "model"],
},
},
},
pdf: {
emoji: "📑",
title: "PDF",
detailKeys: ["path", "paths", "url", "urls", "prompt", "pageRange", "model"],
},
sessions_yield: {
emoji: "⏸️",
title: "Yield",
detailKeys: ["message"],
},
tts: {
emoji: "🔊",
title: "TTS",
detailKeys: ["text", "channel"],
},
},
};
export function serializeToolDisplayConfig(
config: ToolDisplayConfig = TOOL_DISPLAY_CONFIG,
): string {
return `${JSON.stringify(config, null, 2)}\n`;
}

View file

@ -1,236 +0,0 @@
{
"version": 1,
"tools": {
"exec": {
"emoji": "🛠️",
"title": "Exec",
"detailKeys": ["command"]
},
"tool_call": {
"emoji": "🧰",
"title": "Tool Call",
"detailKeys": []
},
"tool_call_update": {
"emoji": "🧰",
"title": "Tool Call",
"detailKeys": []
},
"session_status": {
"emoji": "📊",
"title": "Session Status",
"detailKeys": ["sessionKey", "model"]
},
"sessions_list": {
"emoji": "🗂️",
"title": "Sessions",
"detailKeys": ["kinds", "limit", "activeMinutes", "messageLimit"]
},
"sessions_send": {
"emoji": "📨",
"title": "Session Send",
"detailKeys": ["label", "sessionKey", "agentId", "timeoutSeconds"]
},
"sessions_history": {
"emoji": "🧾",
"title": "Session History",
"detailKeys": ["sessionKey", "limit", "includeTools"]
},
"sessions_spawn": {
"emoji": "🧑‍🔧",
"title": "Sub-agent",
"detailKeys": [
"label",
"task",
"agentId",
"model",
"thinking",
"runTimeoutSeconds",
"cleanup"
]
},
"subagents": {
"emoji": "🤖",
"title": "Subagents",
"actions": {
"list": {
"label": "list",
"detailKeys": ["recentMinutes"]
},
"kill": {
"label": "kill",
"detailKeys": ["target"]
},
"steer": {
"label": "steer",
"detailKeys": ["target"]
}
}
},
"agents_list": {
"emoji": "🧭",
"title": "Agents",
"detailKeys": []
},
"memory_search": {
"emoji": "🧠",
"title": "Memory Search",
"detailKeys": ["query"]
},
"memory_get": {
"emoji": "📓",
"title": "Memory Get",
"detailKeys": ["path", "from", "lines"]
},
"web_search": {
"emoji": "🔎",
"title": "Web Search",
"detailKeys": ["query", "count"]
},
"web_fetch": {
"emoji": "📄",
"title": "Web Fetch",
"detailKeys": ["url", "extractMode", "maxChars"]
},
"code_execution": {
"emoji": "🧮",
"title": "Code Execution",
"detailKeys": ["task"]
},
"message": {
"emoji": "✉️",
"title": "Message",
"actions": {
"send": {
"label": "send",
"detailKeys": ["provider", "to", "media", "replyTo", "threadId"]
},
"poll": {
"label": "poll",
"detailKeys": ["provider", "to", "pollQuestion"]
},
"react": {
"label": "react",
"detailKeys": ["provider", "to", "messageId", "emoji", "remove"]
},
"reactions": {
"label": "reactions",
"detailKeys": ["provider", "to", "messageId", "limit"]
},
"read": {
"label": "read",
"detailKeys": ["provider", "to", "limit"]
},
"edit": {
"label": "edit",
"detailKeys": ["provider", "to", "messageId"]
},
"delete": {
"label": "delete",
"detailKeys": ["provider", "to", "messageId"]
},
"pin": {
"label": "pin",
"detailKeys": ["provider", "to", "messageId"]
},
"unpin": {
"label": "unpin",
"detailKeys": ["provider", "to", "messageId"]
},
"list-pins": {
"label": "list pins",
"detailKeys": ["provider", "to"]
},
"permissions": {
"label": "permissions",
"detailKeys": ["provider", "channelId", "to"]
},
"thread-create": {
"label": "thread create",
"detailKeys": ["provider", "channelId", "threadName"]
},
"thread-list": {
"label": "thread list",
"detailKeys": ["provider", "guildId", "channelId"]
},
"thread-reply": {
"label": "thread reply",
"detailKeys": ["provider", "channelId", "messageId"]
},
"search": {
"label": "search",
"detailKeys": ["provider", "guildId", "query"]
},
"sticker": {
"label": "sticker",
"detailKeys": ["provider", "to", "stickerId"]
},
"member-info": {
"label": "member",
"detailKeys": ["provider", "guildId", "userId"]
},
"role-info": {
"label": "roles",
"detailKeys": ["provider", "guildId"]
},
"emoji-list": {
"label": "emoji list",
"detailKeys": ["provider", "guildId"]
},
"emoji-upload": {
"label": "emoji upload",
"detailKeys": ["provider", "guildId", "emojiName"]
},
"sticker-upload": {
"label": "sticker upload",
"detailKeys": ["provider", "guildId", "stickerName"]
},
"role-add": {
"label": "role add",
"detailKeys": ["provider", "guildId", "userId", "roleId"]
},
"role-remove": {
"label": "role remove",
"detailKeys": ["provider", "guildId", "userId", "roleId"]
},
"channel-info": {
"label": "channel",
"detailKeys": ["provider", "channelId"]
},
"channel-list": {
"label": "channels",
"detailKeys": ["provider", "guildId"]
},
"voice-status": {
"label": "voice",
"detailKeys": ["provider", "guildId", "userId"]
},
"event-list": {
"label": "events",
"detailKeys": ["provider", "guildId"]
},
"event-create": {
"label": "event create",
"detailKeys": ["provider", "guildId", "eventName"]
},
"timeout": {
"label": "timeout",
"detailKeys": ["provider", "guildId", "userId"]
},
"kick": {
"label": "kick",
"detailKeys": ["provider", "guildId", "userId"]
},
"ban": {
"label": "ban",
"detailKeys": ["provider", "guildId", "userId"]
}
}
},
"apply_patch": {
"emoji": "🩹",
"title": "Apply Patch",
"detailKeys": []
}
}
}

View file

@ -1,4 +1,3 @@
import SHARED_TOOL_DISPLAY_JSON from "../../apps/shared/OpenClawKit/Sources/OpenClawKit/Resources/tool-display.json" with { type: "json" };
import { redactToolDetail } from "../logging/redact.js";
import { shortenHomeInString } from "../utils.js";
import {
@ -7,19 +6,8 @@ import {
formatDetailKey,
normalizeToolName,
resolveToolVerbAndDetailForArgs,
type ToolDisplaySpec as ToolDisplaySpecBase,
} from "./tool-display-common.js";
import TOOL_DISPLAY_OVERRIDES_JSON from "./tool-display-overrides.json" with { type: "json" };
type ToolDisplaySpec = ToolDisplaySpecBase & {
emoji?: string;
};
type ToolDisplayConfig = {
version?: number;
fallback?: ToolDisplaySpec;
tools?: Record<string, ToolDisplaySpec>;
};
import { TOOL_DISPLAY_CONFIG } from "./tool-display-config.js";
export type ToolDisplay = {
name: string;
@ -30,11 +18,8 @@ export type ToolDisplay = {
detail?: string;
};
const SHARED_TOOL_DISPLAY_CONFIG = SHARED_TOOL_DISPLAY_JSON as ToolDisplayConfig;
const TOOL_DISPLAY_OVERRIDES = TOOL_DISPLAY_OVERRIDES_JSON as ToolDisplayConfig;
const FALLBACK = TOOL_DISPLAY_OVERRIDES.fallback ??
SHARED_TOOL_DISPLAY_CONFIG.fallback ?? { emoji: "🧩" };
const TOOL_MAP = Object.assign({}, SHARED_TOOL_DISPLAY_CONFIG.tools, TOOL_DISPLAY_OVERRIDES.tools);
const FALLBACK = TOOL_DISPLAY_CONFIG.fallback ?? { emoji: "🧩" };
const TOOL_MAP = TOOL_DISPLAY_CONFIG.tools ?? {};
const DETAIL_LABEL_OVERRIDES: Record<string, string> = {
agentId: "agent",
sessionKey: "session",