refactor(plugin-sdk): consolidate tool result helpers (#99740)

* refactor(plugin-sdk): consolidate tool result helpers

* docs(plugin-sdk): tighten tool result guidance

* refactor(feishu): use tool results directly
This commit is contained in:
Dallin Romney
2026-07-04 16:50:44 -07:00
committed by GitHub
parent c2fc7aa28a
commit bfffa950d7
24 changed files with 105 additions and 152 deletions

View File

@@ -3,6 +3,7 @@ import type * as Lark from "@larksuiteoapi/node-sdk";
import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
import { Type, type TSchema } from "typebox";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { listEnabledFeishuAccounts } from "./accounts.js";
@@ -10,15 +11,6 @@ import { createFeishuClient } from "./client.js";
import { resolveAnyEnabledFeishuToolsConfig, resolveFeishuToolAccount } from "./tool-account.js";
import { resolveToolsConfig } from "./tools-config.js";
// ============ Helpers ============
function json(data: unknown) {
return {
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
details: data,
};
}
type LarkResponse<T = unknown> = { code?: number; msg?: string; data?: T };
type BitableRecordCreatePayload = NonNullable<
Parameters<Lark.Client["bitable"]["appTableRecord"]["create"]>[0]

View File

@@ -1,6 +1,7 @@
// Feishu plugin module implements chat behavior.
import type * as Lark from "@larksuiteoapi/node-sdk";
import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { listEnabledFeishuAccounts } from "./accounts.js";
import { FeishuChatSchema, type FeishuChatParams } from "./chat-schema.js";
@@ -8,13 +9,6 @@ import { createFeishuClient } from "./client.js";
import { formatFeishuApiError } from "./comment-shared.js";
import { resolveToolsConfig } from "./tools-config.js";
function json(data: unknown) {
return {
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
details: data,
};
}
function readChatPageSize(params: Record<string, unknown>): number | undefined {
return readPositiveIntegerParam(params, "page_size", {
max: 100,

View File

@@ -7,6 +7,7 @@ import type * as Lark from "@larksuiteoapi/node-sdk";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
import { normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
import { Type } from "typebox";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { listEnabledFeishuAccounts } from "./accounts.js";
@@ -29,15 +30,6 @@ import {
resolveFeishuToolAccount,
} from "./tool-account.js";
// ============ Helpers ============
function json(data: unknown) {
return {
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
details: data,
};
}
function resolveDocToolLocalRoots(ctx: {
workspaceDir?: string;
fsPolicy?: { workspaceOnly: boolean };

View File

@@ -1,6 +1,7 @@
// Feishu plugin module implements drive behavior.
import type * as Lark from "@larksuiteoapi/node-sdk";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { listEnabledFeishuAccounts } from "./accounts.js";
import { cleanupAmbientCommentTypingReaction } from "./comment-reaction.js";
@@ -14,11 +15,7 @@ import {
import { parseFeishuCommentTarget, type CommentFileType } from "./comment-target.js";
import { FeishuDriveSchema, type FeishuDriveParams } from "./drive-schema.js";
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
import {
jsonToolResult,
toolExecutionErrorResult,
unknownToolActionResult,
} from "./tool-result.js";
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
// ============ Actions ============
@@ -769,33 +766,33 @@ export function registerFeishuDriveTools(api: OpenClawPluginApi) {
});
switch (p.action) {
case "list":
return jsonToolResult(await listFolder(client, p.folder_token));
return jsonResult(await listFolder(client, p.folder_token));
case "info":
return jsonToolResult(await getFileInfo(client, p.file_token));
return jsonResult(await getFileInfo(client, p.file_token));
case "create_folder":
return jsonToolResult(await createFolder(client, p.name, p.folder_token));
return jsonResult(await createFolder(client, p.name, p.folder_token));
case "move":
return jsonToolResult(await moveFile(client, p.file_token, p.type, p.folder_token));
return jsonResult(await moveFile(client, p.file_token, p.type, p.folder_token));
case "delete":
return jsonToolResult(await deleteFile(client, p.file_token, p.type));
return jsonResult(await deleteFile(client, p.file_token, p.type));
case "list_comments": {
const resolved = applyCommentFileTypeDefault(
applyAmbientCommentDefaults(p, ctx),
"list_comments",
);
return jsonToolResult(await listComments(client, resolved));
return jsonResult(await listComments(client, resolved));
}
case "list_comment_replies": {
const resolved = applyCommentFileTypeDefault(
applyAmbientCommentDefaults(p, ctx),
"list_comment_replies",
);
return jsonToolResult(await listCommentReplies(client, resolved));
return jsonResult(await listCommentReplies(client, resolved));
}
case "add_comment": {
const resolved = applyAddCommentDefaults(applyAddCommentAmbientDefaults(p, ctx));
try {
return jsonToolResult(await addComment(client, resolved));
return jsonResult(await addComment(client, resolved));
} finally {
void cleanupAmbientCommentTypingReaction({
client: getDriveInternalClient(client),
@@ -809,7 +806,7 @@ export function registerFeishuDriveTools(api: OpenClawPluginApi) {
"reply_comment",
);
try {
return jsonToolResult(await deliverCommentThreadText(client, resolved));
return jsonResult(await deliverCommentThreadText(client, resolved));
} finally {
void cleanupAmbientCommentTypingReaction({
client: getDriveInternalClient(client),

View File

@@ -1,14 +1,11 @@
// Feishu plugin module implements perm behavior.
import type * as Lark from "@larksuiteoapi/node-sdk";
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { listEnabledFeishuAccounts } from "./accounts.js";
import { FeishuPermSchema, type FeishuPermParams } from "./perm-schema.js";
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
import {
jsonToolResult,
toolExecutionErrorResult,
unknownToolActionResult,
} from "./tool-result.js";
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
type ListTokenType =
| "doc"
@@ -149,13 +146,13 @@ export function registerFeishuPermTools(api: OpenClawPluginApi) {
});
switch (p.action) {
case "list":
return jsonToolResult(await listMembers(client, p.token, p.type));
return jsonResult(await listMembers(client, p.token, p.type));
case "add":
return jsonToolResult(
return jsonResult(
await addMember(client, p.token, p.type, p.member_type, p.member_id, p.perm),
);
case "remove":
return jsonToolResult(
return jsonResult(
await removeMember(client, p.token, p.type, p.member_type, p.member_id),
);
default:

View File

@@ -1,20 +1,8 @@
// Feishu tests cover tool result plugin behavior.
import { describe, expect, it } from "vitest";
import {
jsonToolResult,
toolExecutionErrorResult,
unknownToolActionResult,
} from "./tool-result.js";
describe("jsonToolResult", () => {
it("formats tool result with text content and details", () => {
const payload = { ok: true, id: "abc" };
expect(jsonToolResult(payload)).toEqual({
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
details: payload,
});
});
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
describe("tool result errors", () => {
it("formats unknown action errors", () => {
expect(unknownToolActionResult("create")).toEqual({
content: [

View File

@@ -1,17 +1,11 @@
// Feishu plugin module implements tool result behavior.
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
export function jsonToolResult(data: unknown) {
return {
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
details: data,
};
}
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
export function unknownToolActionResult(action: unknown) {
return jsonToolResult({ error: `Unknown action: ${String(action)}` });
return jsonResult({ error: `Unknown action: ${String(action)}` });
}
export function toolExecutionErrorResult(error: unknown) {
return jsonToolResult({ error: formatErrorMessage(error) });
return jsonResult({ error: formatErrorMessage(error) });
}

View File

@@ -1,14 +1,11 @@
// Feishu plugin module implements wiki behavior.
import type * as Lark from "@larksuiteoapi/node-sdk";
import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
import type { OpenClawPluginApi } from "../runtime-api.js";
import { listEnabledFeishuAccounts } from "./accounts.js";
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
import {
jsonToolResult,
toolExecutionErrorResult,
unknownToolActionResult,
} from "./tool-result.js";
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
import { FeishuWikiSchema, type FeishuWikiParams } from "./wiki-schema.js";
type ObjType = "doc" | "sheet" | "mindnote" | "bitable" | "file" | "docx" | "slides";
@@ -242,12 +239,12 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
});
switch (p.action) {
case "spaces":
return jsonToolResult(
return jsonResult(
await listSpaces(createClient(), readWikiPageSize(p), p.page_token),
);
case "nodes": {
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
return jsonToolResult(
return jsonResult(
await listNodes(
createClient(),
spaceId,
@@ -258,17 +255,17 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
);
}
case "get":
return jsonToolResult(await getNode(createClient(), p.token));
return jsonResult(await getNode(createClient(), p.token));
case "search":
optionalWikiSpaceId(p.space_id, "space_id");
createClient();
return jsonToolResult({
return jsonResult({
error:
"Search is not available. Use feishu_wiki with action: 'nodes' to browse or action: 'get' to lookup by token.",
});
case "create": {
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
return jsonToolResult(
return jsonResult(
await createNode(
createClient(),
spaceId,
@@ -280,7 +277,7 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
}
case "move": {
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
return jsonToolResult(
return jsonResult(
await moveNode(
createClient(),
spaceId,
@@ -292,9 +289,7 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
}
case "rename": {
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
return jsonToolResult(
await renameNode(createClient(), spaceId, p.node_token, p.title),
);
return jsonResult(await renameNode(createClient(), spaceId, p.node_token, p.title));
}
default:
return unknownToolActionResult((p as { action?: unknown }).action);