mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-05 12:33:33 +00:00
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:
@@ -1,2 +1,2 @@
|
||||
01c41d19cf15a0c2759e8f13064ecd5f00360fec467fc8fa47eb1f13907be379 plugin-sdk-api-baseline.json
|
||||
c331d008ecad33627b4d0f08ddeaa6430c51878d0fcaa36c9d61b4656a5f0c78 plugin-sdk-api-baseline.jsonl
|
||||
71520f048737a3bb90fb776e722334bef8e76d4439e68f064e49ff1f261c5698 plugin-sdk-api-baseline.json
|
||||
8398c4a25159f6f073a7418a4bc6472c1f4c1199ca13dd3005b6e9945c5c6a3b plugin-sdk-api-baseline.jsonl
|
||||
|
||||
@@ -84,6 +84,8 @@ export default defineToolPlugin({
|
||||
schema and the generated manifest still includes `configSchema`.
|
||||
- `execute` returns a plain string or JSON-serializable value. The helper wraps
|
||||
it as a text tool result with `details`.
|
||||
- For custom tool results, `openclaw/plugin-sdk/tool-results` exports
|
||||
`textResult` and `jsonResult`.
|
||||
- Tool names are static. `openclaw plugins build` derives `contracts.tools`
|
||||
from the declared tools, so authors do not duplicate names by hand.
|
||||
- Runtime loading stays strict. Installed plugins still need
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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) });
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
||||
import { definePluginEntry, type OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
|
||||
import { Type } from "typebox";
|
||||
import {
|
||||
buildGoogleMeetCalendarDayWindow,
|
||||
@@ -348,13 +349,6 @@ function asParamRecord(params: unknown): Record<string, unknown> {
|
||||
: {};
|
||||
}
|
||||
|
||||
function json(payload: unknown) {
|
||||
return {
|
||||
content: [{ type: "text" as const, text: JSON.stringify(payload, null, 2) }],
|
||||
details: payload,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeTransport(value: unknown): GoogleMeetTransport | undefined {
|
||||
return value === "chrome" || value === "chrome-node" || value === "twilio" ? value : undefined;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
readNonNegativeIntegerParam,
|
||||
readPositiveIntegerParam,
|
||||
} from "openclaw/plugin-sdk/param-readers";
|
||||
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
|
||||
import { Type } from "typebox";
|
||||
import type { OpenClawPluginApi } from "../runtime-api.js";
|
||||
import {
|
||||
@@ -194,10 +195,7 @@ function formatManagedFlowResult(result: ManagedFlowSuccessResult) {
|
||||
flow: result.flow,
|
||||
mutation: result.mutation,
|
||||
};
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(details, null, 2) }],
|
||||
details,
|
||||
};
|
||||
return jsonResult(details);
|
||||
}
|
||||
|
||||
function requireTaskFlowRuntime(taskFlow: BoundTaskFlow | undefined, action: "run" | "resume") {
|
||||
@@ -315,10 +313,7 @@ export function createLobsterTool(api: OpenClawPluginApi, options?: LobsterToolO
|
||||
if (!envelope.ok) {
|
||||
throw new Error(envelope.error.message);
|
||||
}
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(envelope, null, 2) }],
|
||||
details: envelope,
|
||||
};
|
||||
return jsonResult(envelope);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
readResponseTextLimited,
|
||||
} from "openclaw/plugin-sdk/provider-http";
|
||||
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import { debugLog, debugError } from "../utils/log.js";
|
||||
|
||||
@@ -175,13 +176,6 @@ function validateDeleteConfirmation(params: ChannelApiParams): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function json(data: unknown) {
|
||||
return {
|
||||
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
||||
details: data,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Options provided by the caller when executing a channel API request.
|
||||
* 执行频道 API 请求时由调用方提供的选项。
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Qqbot plugin module implements remind logic behavior.
|
||||
import { resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
||||
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
||||
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
|
||||
|
||||
/**
|
||||
* QQBot reminder tool core logic.
|
||||
@@ -259,13 +260,6 @@ export function formatDelay(ms: number): string {
|
||||
return `${hours}h${minutes}m`;
|
||||
}
|
||||
|
||||
function json(data: unknown) {
|
||||
return {
|
||||
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
||||
details: data,
|
||||
};
|
||||
}
|
||||
|
||||
function formatSchedulerError(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { ErrorCodes, errorShape } from "openclaw/plugin-sdk/gateway-runtime";
|
||||
import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { jsonResult as json } from "openclaw/plugin-sdk/tool-results";
|
||||
import { Type } from "typebox";
|
||||
import {
|
||||
definePluginEntry,
|
||||
@@ -710,11 +711,6 @@ export default definePluginEntry({
|
||||
parameters: VoiceCallToolSchema,
|
||||
async execute(_toolCallId, params) {
|
||||
const rawParams = asParamRecord(params);
|
||||
const json = (payload: unknown) => ({
|
||||
content: [{ type: "text" as const, text: JSON.stringify(payload, null, 2) }],
|
||||
details: payload,
|
||||
});
|
||||
|
||||
try {
|
||||
const rt = await ensureRuntime();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { stringEnum } from "openclaw/plugin-sdk/channel-actions";
|
||||
import type { AnyAgentTool, OpenClawPluginToolContext } from "openclaw/plugin-sdk/core";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { jsonResult as json, type AgentToolResult } from "openclaw/plugin-sdk/tool-results";
|
||||
import { Type } from "typebox";
|
||||
import { sendImageZalouser, sendLinkZalouser, sendMessageZalouser } from "./send.js";
|
||||
import { parseZalouserOutboundTarget } from "./session-route.js";
|
||||
@@ -14,11 +15,6 @@ import {
|
||||
|
||||
const ACTIONS = ["send", "image", "link", "friends", "groups", "me", "status"] as const;
|
||||
|
||||
type AgentToolResult = {
|
||||
content: Array<{ type: "text"; text: string }>;
|
||||
details: unknown;
|
||||
};
|
||||
|
||||
const ZalouserToolSchema = Type.Object(
|
||||
{
|
||||
action: stringEnum(ACTIONS, { description: `Action to perform: ${ACTIONS.join(", ")}` }),
|
||||
@@ -44,13 +40,6 @@ type ToolParams = {
|
||||
|
||||
type ZalouserToolContext = Pick<OpenClawPluginToolContext, "deliveryContext">;
|
||||
|
||||
function json(payload: unknown): AgentToolResult {
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
||||
details: payload,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveAmbientZalouserTarget(context?: ZalouserToolContext): {
|
||||
threadId?: string;
|
||||
isGroup?: boolean;
|
||||
@@ -96,7 +85,7 @@ export async function executeZalouserTool(
|
||||
_signal?: AbortSignal,
|
||||
_onUpdate?: unknown,
|
||||
context?: ZalouserToolContext,
|
||||
): Promise<AgentToolResult> {
|
||||
): Promise<AgentToolResult<unknown>> {
|
||||
try {
|
||||
switch (params.action) {
|
||||
case "send": {
|
||||
|
||||
@@ -1433,6 +1433,10 @@
|
||||
"types": "./dist/plugin-sdk/tool-payload.d.ts",
|
||||
"default": "./dist/plugin-sdk/tool-payload.js"
|
||||
},
|
||||
"./plugin-sdk/tool-results": {
|
||||
"types": "./dist/plugin-sdk/tool-results.d.ts",
|
||||
"default": "./dist/plugin-sdk/tool-results.js"
|
||||
},
|
||||
"./plugin-sdk/tool-send": {
|
||||
"types": "./dist/plugin-sdk/tool-send.d.ts",
|
||||
"default": "./dist/plugin-sdk/tool-send.js"
|
||||
|
||||
@@ -108,6 +108,9 @@ export const pluginSdkDocMetadata = {
|
||||
"message-tool-delivery-hints": {
|
||||
category: "runtime",
|
||||
},
|
||||
"tool-results": {
|
||||
category: "utilities",
|
||||
},
|
||||
"provider-selection-runtime": {
|
||||
category: "provider",
|
||||
},
|
||||
|
||||
@@ -329,6 +329,7 @@
|
||||
"text-utility-runtime",
|
||||
"tool-plugin",
|
||||
"tool-payload",
|
||||
"tool-results",
|
||||
"tool-send",
|
||||
"webhook-ingress",
|
||||
"webhook-targets",
|
||||
|
||||
@@ -201,9 +201,9 @@ let budgets;
|
||||
let publicDeprecatedExportsByEntrypointBudget;
|
||||
try {
|
||||
budgets = {
|
||||
publicEntrypoints: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_ENTRYPOINTS", 323),
|
||||
publicExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS", 10425),
|
||||
publicFunctionExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_FUNCTION_EXPORTS", 5237),
|
||||
publicEntrypoints: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_ENTRYPOINTS", 324),
|
||||
publicExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_EXPORTS", 10428),
|
||||
publicFunctionExports: readBudgetEnv("OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_FUNCTION_EXPORTS", 5239),
|
||||
publicDeprecatedExports: readBudgetEnv(
|
||||
"OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_DEPRECATED_EXPORTS",
|
||||
3261,
|
||||
|
||||
@@ -21,6 +21,9 @@ import type {
|
||||
AgentToolUpdateCallback,
|
||||
} from "../runtime/index.js";
|
||||
import { sanitizeToolResultImages } from "../tool-images.js";
|
||||
import { textResult } from "./tool-results.js";
|
||||
|
||||
export { jsonResult, textResult } from "./tool-results.js";
|
||||
|
||||
export type AgentToolWithMeta<TParameters extends TSchema, TResult> = AgentTool<
|
||||
TParameters,
|
||||
@@ -391,18 +394,6 @@ export function stringifyToolPayload(payload: unknown): string {
|
||||
return String(payload);
|
||||
}
|
||||
|
||||
export function textResult<TDetails>(text: string, details: TDetails): AgentToolResult<TDetails> {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text,
|
||||
},
|
||||
],
|
||||
details,
|
||||
};
|
||||
}
|
||||
|
||||
export function failedTextResult<TDetails extends { status: "failed" }>(
|
||||
text: string,
|
||||
details: TDetails,
|
||||
@@ -414,10 +405,6 @@ export function payloadTextResult<TDetails>(payload: TDetails): AgentToolResult<
|
||||
return textResult(stringifyToolPayload(payload), payload);
|
||||
}
|
||||
|
||||
export function jsonResult(payload: unknown): AgentToolResult<unknown> {
|
||||
return textResult(JSON.stringify(payload, null, 2), payload);
|
||||
}
|
||||
|
||||
export type PublicToolProgress = Pick<AgentToolProgress, "text" | "id">;
|
||||
|
||||
export function toolProgressResult(progress: PublicToolProgress): AgentToolResult<undefined> {
|
||||
|
||||
12
src/agents/tools/tool-results.ts
Normal file
12
src/agents/tools/tool-results.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { AgentToolResult } from "../runtime/index.js";
|
||||
|
||||
export function textResult<TDetails>(text: string, details: TDetails): AgentToolResult<TDetails> {
|
||||
return {
|
||||
content: [{ type: "text", text }],
|
||||
details,
|
||||
};
|
||||
}
|
||||
|
||||
export function jsonResult<TDetails>(payload: TDetails): AgentToolResult<TDetails> {
|
||||
return textResult(JSON.stringify(payload, null, 2), payload);
|
||||
}
|
||||
31
src/plugin-sdk/tool-results.test.ts
Normal file
31
src/plugin-sdk/tool-results.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { describe, expect, expectTypeOf, it, vi } from "vitest";
|
||||
|
||||
vi.mock("../agents/tools/common.js", () => {
|
||||
throw new Error("tool-results must not load the broad agent tool helpers");
|
||||
});
|
||||
|
||||
import { jsonResult, textResult, type AgentToolResult } from "./tool-results.js";
|
||||
|
||||
describe("tool result helpers", () => {
|
||||
it("preserves typed JSON details", () => {
|
||||
const payload = { ok: true, messageId: "msg-1" };
|
||||
const result = jsonResult(payload);
|
||||
|
||||
expectTypeOf(result).toEqualTypeOf<AgentToolResult<typeof payload>>();
|
||||
expect(result).toEqual({
|
||||
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
||||
details: payload,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps model text separate from typed details", () => {
|
||||
const details = { ok: true, messageId: "msg-1" };
|
||||
const result = textResult("Message sent.", details);
|
||||
|
||||
expectTypeOf(result).toEqualTypeOf<AgentToolResult<typeof details>>();
|
||||
expect(result).toEqual({
|
||||
content: [{ type: "text", text: "Message sent." }],
|
||||
details,
|
||||
});
|
||||
});
|
||||
});
|
||||
2
src/plugin-sdk/tool-results.ts
Normal file
2
src/plugin-sdk/tool-results.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export type { AgentToolResult } from "../agents/runtime/index.js";
|
||||
export { jsonResult, textResult } from "../agents/tools/tool-results.js";
|
||||
Reference in New Issue
Block a user