From c528f3650775fdae616b4d76e6b5124f39d024e7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 17 May 2026 00:21:42 +0100 Subject: [PATCH] fix(feishu): reject numeric wiki space ids (#82769) (thanks @hyspacex) --- CHANGELOG.md | 1 + extensions/feishu/src/wiki.ts | 79 +++++++++++++++++------------------ 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83bbf48b392..af5c992a8e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Feishu/wiki: reject numeric wiki space IDs before creating Lark clients and keep numeric-looking IDs documented as quoted opaque strings, preventing JavaScript precision loss in knowledge base calls. Fixes #45301. (#82769) Thanks @hyspacex. - Channels/stream previews: contain rejected background draft-stream flushes so preview send failures do not surface as fatal unhandled rejections. Fixes #82712. (#82713) Thanks @coygeek. - Providers/OpenAI Codex: include base `gpt-5.5` and `gpt-5.4` reasoning metadata in the bundled Codex catalog so `/think xhigh` remains available for those models. Fixes #82744. - Providers/MiniMax: declare CN endpoint auth aliases in the plugin manifest so `minimax-cn` and `minimax-portal-cn` reuse the correct base auth profiles instead of falling back to unrelated models after 401s. Fixes #63823. Thanks @kamusis. diff --git a/extensions/feishu/src/wiki.ts b/extensions/feishu/src/wiki.ts index d1f6a8f0141..d4e275a1dcd 100644 --- a/extensions/feishu/src/wiki.ts +++ b/extensions/feishu/src/wiki.ts @@ -39,27 +39,6 @@ function optionalWikiSpaceId(value: unknown, fieldName: string): string | undefi return requireWikiSpaceId(value, fieldName); } -function validateWikiSpaceIds(params: { action?: unknown } & Record): { - spaceId?: string; - targetSpaceId?: string; -} { - switch (params.action) { - case "nodes": - case "create": - case "rename": - return { spaceId: requireWikiSpaceId(params.space_id, "space_id") }; - case "move": - return { - spaceId: requireWikiSpaceId(params.space_id, "space_id"), - targetSpaceId: optionalWikiSpaceId(params.target_space_id, "target_space_id"), - }; - case "search": - return { spaceId: optionalWikiSpaceId(params.space_id, "space_id") }; - default: - return {}; - } -} - async function listSpaces(client: Lark.Client) { const res = await client.wiki.space.list({}); if (res.code !== 0) { @@ -223,42 +202,60 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) { async execute(_toolCallId, params) { const p = params as FeishuWikiExecuteParams; try { - const { spaceId, targetSpaceId } = validateWikiSpaceIds( - p as { action?: unknown } & Record, - ); - const client = createFeishuToolClient({ - api, - executeParams: p, - defaultAccountId, - }); + const createClient = () => + createFeishuToolClient({ + api, + executeParams: p, + defaultAccountId, + }); switch (p.action) { case "spaces": - return jsonToolResult(await listSpaces(client)); - case "nodes": - return jsonToolResult(await listNodes(client, spaceId!, p.parent_node_token)); + return jsonToolResult(await listSpaces(createClient())); + case "nodes": { + const spaceId = requireWikiSpaceId(p.space_id, "space_id"); + return jsonToolResult( + await listNodes(createClient(), spaceId, p.parent_node_token), + ); + } case "get": - return jsonToolResult(await getNode(client, p.token)); + return jsonToolResult(await getNode(createClient(), p.token)); case "search": + optionalWikiSpaceId(p.space_id, "space_id"); + createClient(); return jsonToolResult({ error: "Search is not available. Use feishu_wiki with action: 'nodes' to browse or action: 'get' to lookup by token.", }); - case "create": + case "create": { + const spaceId = requireWikiSpaceId(p.space_id, "space_id"); return jsonToolResult( - await createNode(client, spaceId!, p.title, p.obj_type, p.parent_node_token), + await createNode( + createClient(), + spaceId, + p.title, + p.obj_type, + p.parent_node_token, + ), ); - case "move": + } + case "move": { + const spaceId = requireWikiSpaceId(p.space_id, "space_id"); return jsonToolResult( await moveNode( - client, - spaceId!, + createClient(), + spaceId, p.node_token, - targetSpaceId, + optionalWikiSpaceId(p.target_space_id, "target_space_id"), p.target_parent_token, ), ); - case "rename": - return jsonToolResult(await renameNode(client, spaceId!, p.node_token, p.title)); + } + case "rename": { + const spaceId = requireWikiSpaceId(p.space_id, "space_id"); + return jsonToolResult( + await renameNode(createClient(), spaceId, p.node_token, p.title), + ); + } default: return unknownToolActionResult((p as { action?: unknown }).action); }