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 +181 -1
- package/package.json +4 -2
- package/src/adp-upload-tool.test.ts +122 -0
- package/src/adp-upload-tool.ts +911 -0
- package/src/channel.ts +1 -1
- package/src/monitor.ts +52 -4
- package/src/tool-result-message-blocks.ts +258 -0
- package/uploadfile.pb +33 -0
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.
|
|
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/
|
|
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);
|