adp-openclaw 0.0.30 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
2
  import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
3
- import { adpOpenclawPlugin } from "./src/channel.js";
3
+ import { adpOpenclawPlugin, type AdpOpenclawChannelConfig } from "./src/channel.js";
4
4
  import { setAdpOpenclawRuntime } from "./src/runtime.js";
5
+ import {
6
+ ADP_UPLOAD_TOOL_NAME,
7
+ ADP_UPLOAD_TOOL_SCHEMA,
8
+ parseAdpUploadToolParams,
9
+ uploadFilesToAdpEndpoint,
10
+ type AdpUploadToolResult,
11
+ type UploadedFileInfo,
12
+ } from "./src/adp-upload-tool.js";
5
13
 
6
14
  // Export session history functions for external use
7
15
  export {
@@ -25,6 +33,57 @@ export {
25
33
  type SessionFileConfig,
26
34
  } from "./src/session-history.js";
27
35
 
36
+ // Export ADP upload tool functions and types
37
+ export {
38
+ // Tool name and schema
39
+ ADP_UPLOAD_TOOL_NAME,
40
+ ADP_UPLOAD_TOOL_SCHEMA,
41
+ ADP_UPLOAD_TOOL_MAX_PATHS,
42
+ ADP_UPLOAD_TOOL_MIN_PATHS,
43
+ ADP_UPLOAD_TOOL_MAX_CONCURRENCY,
44
+ ADP_UPLOAD_VALIDATION_MESSAGE,
45
+ // Main functions
46
+ adpUploadFile,
47
+ adpUploadFiles,
48
+ adpUploadFileWithConfig,
49
+ adpUploadFilesWithConfig,
50
+ getStorageCredential,
51
+ uploadFileToCos,
52
+ getSignedDownloadUrl,
53
+ resolveClientToken,
54
+ // Class
55
+ AdpUploader,
56
+ // Tool execution functions
57
+ parseAdpUploadToolParams,
58
+ uploadFilesToAdpEndpoint,
59
+ executeAdpUploadTool,
60
+ // Types
61
+ type UploadResult,
62
+ type AdpUploadToolParams,
63
+ type AdpUploadToolResult,
64
+ type UploadedFileInfo,
65
+ type AdpUploadOptions,
66
+ type DescribeRemoteBotStorageCredentialReq,
67
+ type DescribeRemoteBotStorageCredentialRsp,
68
+ type Credentials,
69
+ } from "./src/adp-upload-tool.js";
70
+
71
+ // Export tool result message blocks functions
72
+ export {
73
+ dispatchToolResultToMessageBlocks,
74
+ buildToolResultSessionContentBlocks,
75
+ formatUploadResultForUser,
76
+ formatUploadResultAsMarkdown,
77
+ type ResourceLinkBlock,
78
+ type TextBlock,
79
+ type ContentBlock,
80
+ type MessageBlock,
81
+ } from "./src/tool-result-message-blocks.js";
82
+
83
+ // Helper to format tool result as JSON string
84
+ const formatToolResultJson = (result: unknown): string =>
85
+ JSON.stringify(result, null, 2) ?? "upload failed";
86
+
28
87
  const plugin = {
29
88
  id: "adp-openclaw",
30
89
  name: "ADP OpenClaw",
@@ -33,6 +92,127 @@ const plugin = {
33
92
  register(api: OpenClawPluginApi) {
34
93
  // console.log("[adp-openclaw] register() called");
35
94
  setAdpOpenclawRuntime(api.runtime);
95
+
96
+ // Register the ADP file upload tool
97
+ // This allows AI to send files to users via ADP storage
98
+ api.registerTool({
99
+ name: ADP_UPLOAD_TOOL_NAME,
100
+ description:
101
+ "If you can see this tool description, you are connected to the ADP server. " +
102
+ "Use this tool to send 1-10 local files of any type (including images and documents) to the user. " +
103
+ "A successful call means the files were uploaded and download URLs are returned. " +
104
+ "Include these URLs in your response so the user can access the files. " +
105
+ "Parameters must be local filesystem paths only.",
106
+ parameters: ADP_UPLOAD_TOOL_SCHEMA,
107
+ async execute(toolCallId: string, params: unknown) {
108
+ // Get bot token from channel config
109
+ const getClientToken = (): string | undefined => {
110
+ try {
111
+ const cfg = api.runtime?.config?.loadConfig?.();
112
+ const channelCfg = cfg?.channels?.["adp-openclaw"] as AdpOpenclawChannelConfig | undefined;
113
+ return channelCfg?.clientToken?.trim() || process.env.ADP_OPENCLAW_CLIENT_TOKEN;
114
+ } catch {
115
+ return process.env.ADP_OPENCLAW_CLIENT_TOKEN;
116
+ }
117
+ };
118
+
119
+ // Parse and validate parameters
120
+ const parsed = parseAdpUploadToolParams(params);
121
+ if (!parsed.ok) {
122
+ const errorResult = {
123
+ ok: false,
124
+ error: formatToolResultJson(parsed.error),
125
+ };
126
+ api.logger.debug?.(`[${ADP_UPLOAD_TOOL_NAME}] validation failed toolCallId=${toolCallId} error=${errorResult.error}`);
127
+ return {
128
+ output: errorResult,
129
+ result: errorResult,
130
+ details: errorResult,
131
+ content: [{ type: "text", text: formatToolResultJson(parsed.error) }],
132
+ isError: true,
133
+ };
134
+ }
135
+
136
+ // Get bot token
137
+ const botToken = getClientToken();
138
+ if (!botToken) {
139
+ const errorResult = {
140
+ ok: false,
141
+ error: "missing bot token for file upload - please configure clientToken in adp-openclaw channel settings",
142
+ };
143
+ api.logger.debug?.(`[${ADP_UPLOAD_TOOL_NAME}] token missing toolCallId=${toolCallId} paths=${JSON.stringify(parsed.value.paths)}`);
144
+ return {
145
+ output: errorResult,
146
+ result: errorResult,
147
+ details: errorResult,
148
+ content: [{ type: "text", text: errorResult.error }],
149
+ isError: true,
150
+ };
151
+ }
152
+
153
+ // Execute upload
154
+ const uploadResult = await uploadFilesToAdpEndpoint(parsed.value.paths, {
155
+ botToken,
156
+ fileType: parsed.value.fileType,
157
+ });
158
+
159
+ if (!uploadResult.ok) {
160
+ const errorResult = {
161
+ ok: false,
162
+ error: formatToolResultJson(uploadResult.error),
163
+ };
164
+ api.logger.debug?.(`[${ADP_UPLOAD_TOOL_NAME}] upload failed toolCallId=${toolCallId} paths=${JSON.stringify(parsed.value.paths)} error=${errorResult.error}`);
165
+ return {
166
+ output: errorResult,
167
+ result: errorResult,
168
+ details: errorResult,
169
+ content: [{ type: "text", text: formatToolResultJson(uploadResult.error) }],
170
+ isError: true,
171
+ };
172
+ }
173
+
174
+ // Success - format result with download URLs
175
+ const successResult: AdpUploadToolResult = {
176
+ ok: true,
177
+ files: uploadResult.files,
178
+ };
179
+
180
+ api.logger.debug?.(`[${ADP_UPLOAD_TOOL_NAME}] upload success toolCallId=${toolCallId} count=${successResult.files?.length ?? 0} paths=${JSON.stringify(parsed.value.paths)}`);
181
+
182
+ // Build content with resource links and download URLs
183
+ const content: Array<{ type: string; uri?: string; name?: string; mimeType?: string; text?: string }> = [];
184
+
185
+ // Add resource links for each file
186
+ for (const file of (successResult.files || [])) {
187
+ content.push({
188
+ type: "resource_link",
189
+ uri: file.uri,
190
+ name: file.name,
191
+ mimeType: file.mimeType,
192
+ });
193
+ }
194
+
195
+ // Add a text summary with download URLs for AI to include in response
196
+ const urlSummary = (successResult.files || [])
197
+ .map((f: UploadedFileInfo) => `- [${f.name}](${f.downloadUrl || f.uri})`)
198
+ .join("\n");
199
+
200
+ content.push({
201
+ type: "text",
202
+ text: `Files uploaded successfully:\n${urlSummary}`,
203
+ });
204
+
205
+ return {
206
+ output: successResult,
207
+ result: successResult,
208
+ details: successResult,
209
+ content,
210
+ isError: false,
211
+ };
212
+ },
213
+ });
214
+
215
+ // Register the channel plugin
36
216
  api.registerChannel({ plugin: adpOpenclawPlugin });
37
217
  },
38
218
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adp-openclaw",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "ADP-OpenClaw demo channel plugin (Go WebSocket backend)",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -8,7 +8,9 @@
8
8
  "zod": "^3.22.4"
9
9
  },
10
10
  "devDependencies": {
11
- "@types/ws": "^8.5.10"
11
+ "@types/node": "^20.11.0",
12
+ "@types/ws": "^8.5.10",
13
+ "typescript": "^5.9.3"
12
14
  },
13
15
  "openclaw": {
14
16
  "extensions": [
@@ -0,0 +1,122 @@
1
+ /**
2
+ * ADP Upload Tool 测试文件
3
+ *
4
+ * 使用方式:
5
+ *
6
+ * 1. 使用环境变量(推荐,与插件配置一致):
7
+ * ADP_OPENCLAW_CLIENT_TOKEN=your-token npx tsx src/adp-upload-tool.test.ts <filePath>
8
+ *
9
+ * 2. 使用命令行参数:
10
+ * npx tsx src/adp-upload-tool.test.ts --token <botToken> <filePath>
11
+ */
12
+
13
+ import { AdpUploader, getStorageCredential } from "./adp-upload-tool.js";
14
+
15
+ async function main() {
16
+ const args = process.argv.slice(2);
17
+
18
+ let botToken: string | undefined;
19
+ let filePaths: string[] = [];
20
+
21
+ // 解析参数
22
+ for (let i = 0; i < args.length; i++) {
23
+ if (args[i] === "--token" && i + 1 < args.length) {
24
+ botToken = args[i + 1];
25
+ i++; // 跳过下一个参数
26
+ } else if (!args[i].startsWith("--")) {
27
+ filePaths.push(args[i]);
28
+ }
29
+ }
30
+
31
+ // 如果没有通过参数传入 token,尝试从环境变量读取
32
+ if (!botToken) {
33
+ botToken = process.env.ADP_OPENCLAW_CLIENT_TOKEN;
34
+ }
35
+
36
+ if (filePaths.length === 0) {
37
+ console.log("ADP Upload Tool 测试");
38
+ console.log("");
39
+ console.log("使用方式:");
40
+ console.log(" 1. 使用环境变量(推荐,与插件配置一致):");
41
+ console.log(" ADP_OPENCLAW_CLIENT_TOKEN=your-token npx tsx src/adp-upload-tool.test.ts <filePath>");
42
+ console.log("");
43
+ console.log(" 2. 使用命令行参数:");
44
+ console.log(" npx tsx src/adp-upload-tool.test.ts --token <botToken> <filePath>");
45
+ console.log("");
46
+ console.log("示例:");
47
+ console.log(" npx tsx src/adp-upload-tool.test.ts --token my-bot-token ./test.txt");
48
+ console.log(" ADP_OPENCLAW_CLIENT_TOKEN=my-token npx tsx src/adp-upload-tool.test.ts ./file1.txt ./file2.pdf");
49
+ process.exit(1);
50
+ }
51
+
52
+ if (!botToken) {
53
+ console.error("错误: 未提供 botToken");
54
+ console.error("请通过 --token 参数或 ADP_OPENCLAW_CLIENT_TOKEN 环境变量设置");
55
+ process.exit(1);
56
+ }
57
+
58
+ console.log("=".repeat(60));
59
+ console.log("ADP Upload Tool 测试");
60
+ console.log("=".repeat(60));
61
+ console.log(`Bot Token: ${botToken.substring(0, 10)}...`);
62
+ console.log(`文件列表: ${filePaths.join(", ")}`);
63
+ console.log("");
64
+
65
+ // 测试获取临时密钥
66
+ console.log("1. 测试获取临时密钥...");
67
+ try {
68
+ const credential = await getStorageCredential(botToken);
69
+ console.log(" ✓ 获取密钥成功");
70
+ console.log(` - Bucket: ${credential.bucket}`);
71
+ console.log(` - Region: ${credential.region}`);
72
+ console.log(` - File Path: ${credential.file_path}`);
73
+ console.log(` - Secret ID: ${credential.credentials.tmp_secret_id.substring(0, 10)}...`);
74
+ console.log(` - 有效期至: ${new Date(credential.expired_time * 1000).toLocaleString()}`);
75
+ console.log("");
76
+ } catch (error) {
77
+ console.log(" ✗ 获取密钥失败");
78
+ console.log(` - 错误: ${error instanceof Error ? error.message : error}`);
79
+ process.exit(1);
80
+ }
81
+
82
+ // 使用 AdpUploader 类测试上传
83
+ console.log("2. 使用 AdpUploader 测试上传...");
84
+ const uploader = new AdpUploader({ clientToken: botToken });
85
+ console.log(` - 配置状态: ${uploader.isConfigured() ? "已配置" : "未配置"}`);
86
+ console.log(` - Token 预览: ${uploader.getTokenPreview()}`);
87
+ console.log("");
88
+
89
+ if (filePaths.length === 1) {
90
+ // 单文件上传
91
+ console.log("3. 测试单文件上传...");
92
+ const result = await uploader.upload(filePaths[0]);
93
+ if (result.ok) {
94
+ console.log(" ✓ 上传成功");
95
+ console.log(` - 下载链接: ${result.fileUrl}`);
96
+ } else {
97
+ console.log(" ✗ 上传失败");
98
+ console.log(` - 错误: ${result.error}`);
99
+ }
100
+ } else {
101
+ // 批量上传
102
+ console.log("3. 测试批量上传...");
103
+ const results = await uploader.uploadMultiple(filePaths);
104
+ results.forEach((result, index) => {
105
+ const filePath = filePaths[index];
106
+ if (result.ok) {
107
+ console.log(` ✓ [${filePath}] 上传成功`);
108
+ console.log(` 下载链接: ${result.fileUrl}`);
109
+ } else {
110
+ console.log(` ✗ [${filePath}] 上传失败`);
111
+ console.log(` 错误: ${result.error}`);
112
+ }
113
+ });
114
+ }
115
+
116
+ console.log("");
117
+ console.log("=".repeat(60));
118
+ console.log("测试完成");
119
+ console.log("=".repeat(60));
120
+ }
121
+
122
+ main().catch(console.error);