Skip to content

Commit bfffa95

Browse files
authored
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
1 parent c2fc7aa commit bfffa95

24 files changed

Lines changed: 105 additions & 152 deletions
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
01c41d19cf15a0c2759e8f13064ecd5f00360fec467fc8fa47eb1f13907be379 plugin-sdk-api-baseline.json
2-
c331d008ecad33627b4d0f08ddeaa6430c51878d0fcaa36c9d61b4656a5f0c78 plugin-sdk-api-baseline.jsonl
1+
71520f048737a3bb90fb776e722334bef8e76d4439e68f064e49ff1f261c5698 plugin-sdk-api-baseline.json
2+
8398c4a25159f6f073a7418a4bc6472c1f4c1199ca13dd3005b6e9945c5c6a3b plugin-sdk-api-baseline.jsonl

docs/plugins/sdk-entrypoints.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ export default defineToolPlugin({
8484
schema and the generated manifest still includes `configSchema`.
8585
- `execute` returns a plain string or JSON-serializable value. The helper wraps
8686
it as a text tool result with `details`.
87+
- For custom tool results, `openclaw/plugin-sdk/tool-results` exports
88+
`textResult` and `jsonResult`.
8789
- Tool names are static. `openclaw plugins build` derives `contracts.tools`
8890
from the declared tools, so authors do not duplicate names by hand.
8991
- Runtime loading stays strict. Installed plugins still need

extensions/feishu/src/bitable.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,14 @@ import type * as Lark from "@larksuiteoapi/node-sdk";
33
import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
44
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
55
import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
6+
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
67
import { Type, type TSchema } from "typebox";
78
import type { OpenClawPluginApi } from "../runtime-api.js";
89
import { listEnabledFeishuAccounts } from "./accounts.js";
910
import { createFeishuClient } from "./client.js";
1011
import { resolveAnyEnabledFeishuToolsConfig, resolveFeishuToolAccount } from "./tool-account.js";
1112
import { resolveToolsConfig } from "./tools-config.js";
1213

13-
// ============ Helpers ============
14-
15-
function json(data: unknown) {
16-
return {
17-
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
18-
details: data,
19-
};
20-
}
21-
2214
type LarkResponse<T = unknown> = { code?: number; msg?: string; data?: T };
2315
type BitableRecordCreatePayload = NonNullable<
2416
Parameters<Lark.Client["bitable"]["appTableRecord"]["create"]>[0]

extensions/feishu/src/chat.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
// Feishu plugin module implements chat behavior.
22
import type * as Lark from "@larksuiteoapi/node-sdk";
33
import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
4+
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
45
import type { OpenClawPluginApi } from "../runtime-api.js";
56
import { listEnabledFeishuAccounts } from "./accounts.js";
67
import { FeishuChatSchema, type FeishuChatParams } from "./chat-schema.js";
78
import { createFeishuClient } from "./client.js";
89
import { formatFeishuApiError } from "./comment-shared.js";
910
import { resolveToolsConfig } from "./tools-config.js";
1011

11-
function json(data: unknown) {
12-
return {
13-
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
14-
details: data,
15-
};
16-
}
17-
1812
function readChatPageSize(params: Record<string, unknown>): number | undefined {
1913
return readPositiveIntegerParam(params, "page_size", {
2014
max: 100,

extensions/feishu/src/docx.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type * as Lark from "@larksuiteoapi/node-sdk";
77
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
88
import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
99
import { normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
10+
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
1011
import { Type } from "typebox";
1112
import type { OpenClawPluginApi } from "../runtime-api.js";
1213
import { listEnabledFeishuAccounts } from "./accounts.js";
@@ -29,15 +30,6 @@ import {
2930
resolveFeishuToolAccount,
3031
} from "./tool-account.js";
3132

32-
// ============ Helpers ============
33-
34-
function json(data: unknown) {
35-
return {
36-
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
37-
details: data,
38-
};
39-
}
40-
4133
function resolveDocToolLocalRoots(ctx: {
4234
workspaceDir?: string;
4335
fsPolicy?: { workspaceOnly: boolean };

extensions/feishu/src/drive.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Feishu plugin module implements drive behavior.
22
import type * as Lark from "@larksuiteoapi/node-sdk";
33
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
4+
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
45
import type { OpenClawPluginApi } from "../runtime-api.js";
56
import { listEnabledFeishuAccounts } from "./accounts.js";
67
import { cleanupAmbientCommentTypingReaction } from "./comment-reaction.js";
@@ -14,11 +15,7 @@ import {
1415
import { parseFeishuCommentTarget, type CommentFileType } from "./comment-target.js";
1516
import { FeishuDriveSchema, type FeishuDriveParams } from "./drive-schema.js";
1617
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
17-
import {
18-
jsonToolResult,
19-
toolExecutionErrorResult,
20-
unknownToolActionResult,
21-
} from "./tool-result.js";
18+
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
2219

2320
// ============ Actions ============
2421

@@ -769,33 +766,33 @@ export function registerFeishuDriveTools(api: OpenClawPluginApi) {
769766
});
770767
switch (p.action) {
771768
case "list":
772-
return jsonToolResult(await listFolder(client, p.folder_token));
769+
return jsonResult(await listFolder(client, p.folder_token));
773770
case "info":
774-
return jsonToolResult(await getFileInfo(client, p.file_token));
771+
return jsonResult(await getFileInfo(client, p.file_token));
775772
case "create_folder":
776-
return jsonToolResult(await createFolder(client, p.name, p.folder_token));
773+
return jsonResult(await createFolder(client, p.name, p.folder_token));
777774
case "move":
778-
return jsonToolResult(await moveFile(client, p.file_token, p.type, p.folder_token));
775+
return jsonResult(await moveFile(client, p.file_token, p.type, p.folder_token));
779776
case "delete":
780-
return jsonToolResult(await deleteFile(client, p.file_token, p.type));
777+
return jsonResult(await deleteFile(client, p.file_token, p.type));
781778
case "list_comments": {
782779
const resolved = applyCommentFileTypeDefault(
783780
applyAmbientCommentDefaults(p, ctx),
784781
"list_comments",
785782
);
786-
return jsonToolResult(await listComments(client, resolved));
783+
return jsonResult(await listComments(client, resolved));
787784
}
788785
case "list_comment_replies": {
789786
const resolved = applyCommentFileTypeDefault(
790787
applyAmbientCommentDefaults(p, ctx),
791788
"list_comment_replies",
792789
);
793-
return jsonToolResult(await listCommentReplies(client, resolved));
790+
return jsonResult(await listCommentReplies(client, resolved));
794791
}
795792
case "add_comment": {
796793
const resolved = applyAddCommentDefaults(applyAddCommentAmbientDefaults(p, ctx));
797794
try {
798-
return jsonToolResult(await addComment(client, resolved));
795+
return jsonResult(await addComment(client, resolved));
799796
} finally {
800797
void cleanupAmbientCommentTypingReaction({
801798
client: getDriveInternalClient(client),
@@ -809,7 +806,7 @@ export function registerFeishuDriveTools(api: OpenClawPluginApi) {
809806
"reply_comment",
810807
);
811808
try {
812-
return jsonToolResult(await deliverCommentThreadText(client, resolved));
809+
return jsonResult(await deliverCommentThreadText(client, resolved));
813810
} finally {
814811
void cleanupAmbientCommentTypingReaction({
815812
client: getDriveInternalClient(client),

extensions/feishu/src/perm.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
// Feishu plugin module implements perm behavior.
22
import type * as Lark from "@larksuiteoapi/node-sdk";
3+
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
34
import type { OpenClawPluginApi } from "../runtime-api.js";
45
import { listEnabledFeishuAccounts } from "./accounts.js";
56
import { FeishuPermSchema, type FeishuPermParams } from "./perm-schema.js";
67
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
7-
import {
8-
jsonToolResult,
9-
toolExecutionErrorResult,
10-
unknownToolActionResult,
11-
} from "./tool-result.js";
8+
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
129

1310
type ListTokenType =
1411
| "doc"
@@ -149,13 +146,13 @@ export function registerFeishuPermTools(api: OpenClawPluginApi) {
149146
});
150147
switch (p.action) {
151148
case "list":
152-
return jsonToolResult(await listMembers(client, p.token, p.type));
149+
return jsonResult(await listMembers(client, p.token, p.type));
153150
case "add":
154-
return jsonToolResult(
151+
return jsonResult(
155152
await addMember(client, p.token, p.type, p.member_type, p.member_id, p.perm),
156153
);
157154
case "remove":
158-
return jsonToolResult(
155+
return jsonResult(
159156
await removeMember(client, p.token, p.type, p.member_type, p.member_id),
160157
);
161158
default:

extensions/feishu/src/tool-result.test.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
// Feishu tests cover tool result plugin behavior.
22
import { describe, expect, it } from "vitest";
3-
import {
4-
jsonToolResult,
5-
toolExecutionErrorResult,
6-
unknownToolActionResult,
7-
} from "./tool-result.js";
8-
9-
describe("jsonToolResult", () => {
10-
it("formats tool result with text content and details", () => {
11-
const payload = { ok: true, id: "abc" };
12-
expect(jsonToolResult(payload)).toEqual({
13-
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
14-
details: payload,
15-
});
16-
});
3+
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
174

5+
describe("tool result errors", () => {
186
it("formats unknown action errors", () => {
197
expect(unknownToolActionResult("create")).toEqual({
208
content: [
Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
// Feishu plugin module implements tool result behavior.
22
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
3-
4-
export function jsonToolResult(data: unknown) {
5-
return {
6-
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
7-
details: data,
8-
};
9-
}
3+
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
104

115
export function unknownToolActionResult(action: unknown) {
12-
return jsonToolResult({ error: `Unknown action: ${String(action)}` });
6+
return jsonResult({ error: `Unknown action: ${String(action)}` });
137
}
148

159
export function toolExecutionErrorResult(error: unknown) {
16-
return jsonToolResult({ error: formatErrorMessage(error) });
10+
return jsonResult({ error: formatErrorMessage(error) });
1711
}

extensions/feishu/src/wiki.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
// Feishu plugin module implements wiki behavior.
22
import type * as Lark from "@larksuiteoapi/node-sdk";
33
import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
4+
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
45
import type { OpenClawPluginApi } from "../runtime-api.js";
56
import { listEnabledFeishuAccounts } from "./accounts.js";
67
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
7-
import {
8-
jsonToolResult,
9-
toolExecutionErrorResult,
10-
unknownToolActionResult,
11-
} from "./tool-result.js";
8+
import { toolExecutionErrorResult, unknownToolActionResult } from "./tool-result.js";
129
import { FeishuWikiSchema, type FeishuWikiParams } from "./wiki-schema.js";
1310

1411
type ObjType = "doc" | "sheet" | "mindnote" | "bitable" | "file" | "docx" | "slides";
@@ -242,12 +239,12 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
242239
});
243240
switch (p.action) {
244241
case "spaces":
245-
return jsonToolResult(
242+
return jsonResult(
246243
await listSpaces(createClient(), readWikiPageSize(p), p.page_token),
247244
);
248245
case "nodes": {
249246
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
250-
return jsonToolResult(
247+
return jsonResult(
251248
await listNodes(
252249
createClient(),
253250
spaceId,
@@ -258,17 +255,17 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
258255
);
259256
}
260257
case "get":
261-
return jsonToolResult(await getNode(createClient(), p.token));
258+
return jsonResult(await getNode(createClient(), p.token));
262259
case "search":
263260
optionalWikiSpaceId(p.space_id, "space_id");
264261
createClient();
265-
return jsonToolResult({
262+
return jsonResult({
266263
error:
267264
"Search is not available. Use feishu_wiki with action: 'nodes' to browse or action: 'get' to lookup by token.",
268265
});
269266
case "create": {
270267
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
271-
return jsonToolResult(
268+
return jsonResult(
272269
await createNode(
273270
createClient(),
274271
spaceId,
@@ -280,7 +277,7 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
280277
}
281278
case "move": {
282279
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
283-
return jsonToolResult(
280+
return jsonResult(
284281
await moveNode(
285282
createClient(),
286283
spaceId,
@@ -292,9 +289,7 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
292289
}
293290
case "rename": {
294291
const spaceId = requireWikiSpaceId(p.space_id, "space_id");
295-
return jsonToolResult(
296-
await renameNode(createClient(), spaceId, p.node_token, p.title),
297-
);
292+
return jsonResult(await renameNode(createClient(), spaceId, p.node_token, p.title));
298293
}
299294
default:
300295
return unknownToolActionResult((p as { action?: unknown }).action);

0 commit comments

Comments
 (0)