@vectorx/xhs-cloud-cli 0.6.0 → 1.0.0

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.
Files changed (52) hide show
  1. package/bin/rcb.js +47 -157
  2. package/lib/commands/agent/dev.js +3 -0
  3. package/lib/commands/auth/login.js +13 -0
  4. package/lib/commands/env/create.js +156 -0
  5. package/lib/commands/env/index.js +20 -0
  6. package/lib/commands/env/info.js +106 -0
  7. package/lib/commands/env/list.js +93 -0
  8. package/lib/commands/env/set.js +129 -0
  9. package/lib/commands/fun/deploy.js +182 -0
  10. package/lib/commands/fun/dev.js +183 -0
  11. package/lib/commands/fun/index.js +20 -0
  12. package/lib/commands/fun/list.js +77 -0
  13. package/lib/commands/fun/new.js +125 -0
  14. package/lib/commands/index.js +2 -0
  15. package/lib/constants/cmd.js +9 -9
  16. package/lib/core/base.js +75 -1
  17. package/lib/decorators/auth.js +6 -0
  18. package/lib/decorators/captureError.js +1 -0
  19. package/lib/main.js +6 -0
  20. package/package.json +7 -6
  21. package/templates/ai-cloud-functions-example/.env.template +1 -0
  22. package/templates/ai-cloud-functions-example/README.md +277 -0
  23. package/templates/ai-cloud-functions-example/agent-cloudbase-functions.json +83 -0
  24. package/templates/ai-cloud-functions-example/package.json +10 -0
  25. package/templates/ai-cloud-functions-example/src/binary/index.js +207 -0
  26. package/templates/ai-cloud-functions-example/src/context/context-service.js +94 -0
  27. package/templates/ai-cloud-functions-example/src/context/index.js +57 -0
  28. package/templates/ai-cloud-functions-example/src/env/index.js +264 -0
  29. package/templates/ai-cloud-functions-example/src/form/index.js +138 -0
  30. package/templates/ai-cloud-functions-example/src/index.js +0 -0
  31. package/templates/ai-cloud-functions-example/src/json/index.js +194 -0
  32. package/templates/ai-cloud-functions-example/src/multipart/index.js +189 -0
  33. package/templates/ai-cloud-functions-example/src/text/index.js +319 -0
  34. package/templates/ai-cloud-functions-example/src/user/index.js +82 -0
  35. package/templates/chatbox-agent/project.config.json +2 -2
  36. package/templates/cloudfunction-template/.env.template +2 -0
  37. package/templates/cloudfunction-template/agent-cloudbase-functions.json +17 -0
  38. package/templates/cloudfunction-template/package.json +11 -0
  39. package/templates/cloudfunction-template/project.config.json +5 -0
  40. package/templates/cloudfunction-template/src/echo.js +27 -0
  41. package/templates/cloudfunction-template/src/index.js +34 -0
  42. package/types/commands/env/create.d.ts +19 -0
  43. package/types/commands/env/index.d.ts +4 -0
  44. package/types/commands/env/info.d.ts +14 -0
  45. package/types/commands/env/list.d.ts +11 -0
  46. package/types/commands/env/set.d.ts +14 -0
  47. package/types/commands/fun/deploy.d.ts +14 -0
  48. package/types/commands/fun/dev.d.ts +14 -0
  49. package/types/commands/fun/index.d.ts +4 -0
  50. package/types/commands/fun/list.d.ts +14 -0
  51. package/types/commands/fun/new.d.ts +16 -0
  52. package/types/commands/index.d.ts +2 -0
@@ -0,0 +1,189 @@
1
+ /**
2
+ * 文件上传处理示例函数
3
+ *
4
+ * 覆盖场景:
5
+ * - Content-Type: multipart/form-data
6
+ *
7
+ * 业务场景:文件上传,模拟保存到数据库或 OSS
8
+ */
9
+
10
+ // Mock 文件存储记录(模拟数据库)
11
+ const FILE_RECORDS = [];
12
+
13
+ /**
14
+ * POST 请求:上传文件
15
+ *
16
+ * 示例:
17
+ * - POST /multipart/upload
18
+ * - Content-Type: multipart/form-data
19
+ * - Body: FormData with file field
20
+ */
21
+ exports.multipartUpload = async function multipartUpload(event, context) {
22
+ console.log('[multipartUpload] 函数调用开始', {
23
+ ctxId: context?.ctxId,
24
+ eventID: context?.eventID,
25
+ timestamp: new Date().toISOString(),
26
+ });
27
+
28
+ // 对齐抖音云托管:multipart/form-data 会被解析进 event.params(对象)
29
+ // 文件字段可能是 Buffer、base64 字符串或已处理的对象
30
+ const formData = (event && event.params) || {};
31
+
32
+ // 提取文件信息
33
+ const file = formData.file || formData.upload || formData.fileData;
34
+ const fileName = formData.fileName || formData.filename || 'unknown';
35
+ const fileType = formData.fileType || formData.contentType || 'application/octet-stream';
36
+ const description = formData.description || '';
37
+
38
+ console.log('[multipartUpload] 文件信息', {
39
+ fileName,
40
+ fileType,
41
+ hasFile: !!file,
42
+ hasDescription: !!description,
43
+ fileDataType: file ? (Buffer.isBuffer(file) ? 'Buffer' : typeof file) : 'none',
44
+ });
45
+
46
+ if (!file) {
47
+ console.log('[multipartUpload] 错误:未找到文件数据');
48
+ return {
49
+ ok: false,
50
+ code: 400,
51
+ message: "MISSING_FILE",
52
+ detail: "未找到文件数据,请确保表单中包含 file 字段",
53
+ };
54
+ }
55
+
56
+ // 处理文件数据
57
+ let fileBuffer;
58
+ let fileSize = 0;
59
+
60
+ if (Buffer.isBuffer(file)) {
61
+ fileBuffer = file;
62
+ fileSize = file.length;
63
+ console.log('[multipartUpload] 文件格式:Buffer', { size: fileSize });
64
+ } else if (typeof file === 'string') {
65
+ // 如果是 base64 字符串
66
+ fileBuffer = Buffer.from(file, 'base64');
67
+ fileSize = fileBuffer.length;
68
+ console.log('[multipartUpload] 文件格式:base64 字符串', { size: fileSize });
69
+ } else if (file && file.data) {
70
+ // 如果文件被包装在对象中
71
+ fileBuffer = Buffer.isBuffer(file.data) ? file.data : Buffer.from(file.data);
72
+ fileSize = fileBuffer.length;
73
+ console.log('[multipartUpload] 文件格式:包装对象', { size: fileSize });
74
+ } else {
75
+ console.log('[multipartUpload] 错误:无法解析文件数据格式');
76
+ return {
77
+ ok: false,
78
+ code: 400,
79
+ message: "INVALID_FILE_FORMAT",
80
+ detail: "无法解析文件数据格式",
81
+ };
82
+ }
83
+
84
+ // 模拟保存到 OSS(这里只是记录元数据)
85
+ const fileId = `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
86
+ const ossUrl = `https://oss.example.com/files/${fileId}`;
87
+
88
+ console.log('[multipartUpload] 生成文件 ID 和 OSS URL', { fileId, ossUrl });
89
+
90
+ // 模拟数据库保存文件元数据
91
+ const fileRecord = {
92
+ id: fileId,
93
+ fileName,
94
+ fileType,
95
+ fileSize,
96
+ description,
97
+ ossUrl,
98
+ uploadedAt: new Date().toISOString(),
99
+ // 实际场景中,文件内容会保存到 OSS,这里只保存元数据
100
+ // fileContent: fileBuffer.toString('base64'), // 仅用于测试,实际不存储
101
+ };
102
+ FILE_RECORDS.push(fileRecord);
103
+
104
+ console.log('[multipartUpload] 文件上传成功', {
105
+ fileId,
106
+ fileName,
107
+ fileSize,
108
+ ossUrl,
109
+ totalFiles: FILE_RECORDS.length,
110
+ });
111
+
112
+ return {
113
+ ok: true,
114
+ code: 0,
115
+ message: "MULTIPART_UPLOAD_OK",
116
+ data: {
117
+ fileId,
118
+ fileName,
119
+ fileType,
120
+ fileSize,
121
+ ossUrl,
122
+ uploadedAt: fileRecord.uploadedAt,
123
+ },
124
+ contentType: "multipart/form-data",
125
+ // 模拟业务逻辑:返回文件访问信息
126
+ businessLogic: {
127
+ savedToDatabase: true,
128
+ uploadedToOSS: true,
129
+ canAccess: true,
130
+ },
131
+ meta: {
132
+ ctxId: context.ctxId,
133
+ eventID: context.eventID,
134
+ eventType: context.eventType,
135
+ },
136
+ };
137
+ };
138
+
139
+ /**
140
+ * GET 请求:查询文件列表
141
+ *
142
+ * 示例:
143
+ * - GET /multipart/files?fileType=image/png
144
+ */
145
+ exports.multipartFiles = async function multipartFiles(event, context) {
146
+ console.log('[multipartFiles] 函数调用开始', {
147
+ ctxId: context?.ctxId,
148
+ eventID: context?.eventID,
149
+ timestamp: new Date().toISOString(),
150
+ });
151
+
152
+ const query = (event && event.params) || {};
153
+ const { fileType } = query;
154
+
155
+ console.log('[multipartFiles] 查询参数', { fileType, totalFiles: FILE_RECORDS.length });
156
+
157
+ let files = FILE_RECORDS;
158
+
159
+ // 模拟数据库查询:按文件类型过滤
160
+ if (fileType) {
161
+ files = FILE_RECORDS.filter(f => f.fileType === fileType);
162
+ console.log('[multipartFiles] 按文件类型过滤', { fileType, filteredCount: files.length });
163
+ }
164
+
165
+ console.log('[multipartFiles] 查询结果', { total: files.length });
166
+
167
+ return {
168
+ ok: true,
169
+ code: 0,
170
+ message: "MULTIPART_FILES_OK",
171
+ data: {
172
+ total: files.length,
173
+ files: files.map(f => ({
174
+ id: f.id,
175
+ fileName: f.fileName,
176
+ fileType: f.fileType,
177
+ fileSize: f.fileSize,
178
+ ossUrl: f.ossUrl,
179
+ uploadedAt: f.uploadedAt,
180
+ })),
181
+ },
182
+ contentType: "multipart/form-data",
183
+ meta: {
184
+ ctxId: context.ctxId,
185
+ eventID: context.eventID,
186
+ eventType: context.eventType,
187
+ },
188
+ };
189
+ };
@@ -0,0 +1,319 @@
1
+ /**
2
+ * 文本数据处理示例函数
3
+ *
4
+ * 覆盖场景:
5
+ * - Content-Type: text/plain
6
+ * - Content-Type: text/html
7
+ * - Content-Type: text/xml
8
+ * - 默认 text(未指定 content-type)
9
+ *
10
+ * 业务场景:处理文本数据,模拟日志记录、文本分析等
11
+ */
12
+
13
+ // Mock 文本日志记录
14
+ const TEXT_LOGS = [];
15
+
16
+ /**
17
+ * POST 请求:提交文本内容
18
+ *
19
+ * 示例:
20
+ * - POST /text/submit
21
+ * - Content-Type: text/plain
22
+ * - Body: "这是一段文本内容"
23
+ */
24
+ exports.textSubmit = async function textSubmit(event, context) {
25
+ console.log('[textSubmit] event', JSON.stringify(event, null, 2));
26
+ console.log('[textSubmit] 函数调用开始', {
27
+ ctxId: context?.ctxId,
28
+ eventID: context?.eventID,
29
+ eventType: context?.eventType,
30
+ timestamp: context?.timestamp,
31
+ httpContext: context?.httpContext,
32
+ baseUrl: context?.baseUrl,
33
+ });
34
+
35
+ // 对齐抖音云托管:文本内容从 event.params 中获取(string 或 object)
36
+ let textContent = '';
37
+
38
+ const params = event?.params;
39
+
40
+ if (typeof params === 'string') {
41
+ textContent = params;
42
+ console.log('[textSubmit] 数据格式:event.params 是字符串');
43
+ } else if (params && typeof params.text === 'string') {
44
+ textContent = params.text;
45
+ console.log('[textSubmit] 数据格式:event.params.text 是字符串');
46
+ } else {
47
+ console.log('[textSubmit] 错误:无法解析文本数据格式');
48
+ return {
49
+ ok: false,
50
+ code: 400,
51
+ message: "INVALID_TEXT_DATA",
52
+ detail: "无法解析文本数据",
53
+ };
54
+ }
55
+
56
+ if (!textContent || textContent.trim().length === 0) {
57
+ console.log('[textSubmit] 错误:文本内容为空');
58
+ return {
59
+ ok: false,
60
+ code: 400,
61
+ message: "EMPTY_TEXT",
62
+ detail: "文本内容为空",
63
+ };
64
+ }
65
+
66
+ // 检测内容类型
67
+ const contentType = context.httpContext?.headers?.['content-type'] || 'text/plain';
68
+ let detectedType = 'text/plain';
69
+
70
+ if (contentType.includes('text/html')) {
71
+ detectedType = 'text/html';
72
+ } else if (contentType.includes('text/xml')) {
73
+ detectedType = 'text/xml';
74
+ } else if (contentType.includes('text/plain')) {
75
+ detectedType = 'text/plain';
76
+ }
77
+
78
+ console.log('[textSubmit] 内容类型检测', {
79
+ contentType,
80
+ detectedType,
81
+ textLength: textContent.length,
82
+ });
83
+
84
+ // 模拟文本分析(字数统计、关键词提取等)
85
+ const wordCount = textContent.trim().split(/\s+/).length;
86
+ const charCount = textContent.length;
87
+ const lines = textContent.split('\n').length;
88
+
89
+ // 简单的关键词提取(示例)
90
+ const keywords = textContent
91
+ .toLowerCase()
92
+ .replace(/[^\w\s]/g, ' ')
93
+ .split(/\s+/)
94
+ .filter(w => w.length > 3)
95
+ .slice(0, 5);
96
+
97
+ console.log('[textSubmit] 文本分析结果', {
98
+ wordCount,
99
+ charCount,
100
+ lines,
101
+ keywords,
102
+ });
103
+
104
+ // 模拟保存到数据库
105
+ const logEntry = {
106
+ id: `log_${Date.now()}`,
107
+ contentType: detectedType,
108
+ textContent: textContent.substring(0, 500), // 只保存前500字符
109
+ fullLength: textContent.length,
110
+ wordCount,
111
+ charCount,
112
+ lines,
113
+ keywords,
114
+ submittedAt: new Date().toISOString(),
115
+ };
116
+ TEXT_LOGS.push(logEntry);
117
+
118
+ console.log('[textSubmit] 文本提交成功', {
119
+ logId: logEntry.id,
120
+ contentType: detectedType,
121
+ totalLogs: TEXT_LOGS.length,
122
+ });
123
+
124
+ return {
125
+ ok: true,
126
+ code: 0,
127
+ message: "TEXT_SUBMIT_OK",
128
+ data: {
129
+ logId: logEntry.id,
130
+ contentType: detectedType,
131
+ analysis: {
132
+ wordCount,
133
+ charCount,
134
+ lines,
135
+ keywords,
136
+ },
137
+ submittedAt: logEntry.submittedAt,
138
+ },
139
+ contentType: detectedType,
140
+ meta: {
141
+ ctxId: context.ctxId,
142
+ eventID: context.eventID,
143
+ eventType: context.eventType,
144
+ },
145
+ };
146
+ };
147
+
148
+ /**
149
+ * GET 请求:查询文本日志
150
+ *
151
+ * 示例:
152
+ * - GET /text/logs?contentType=text/plain
153
+ */
154
+ exports.textLogs = async function textLogs(event, context) {
155
+ console.log('[textLogs] 函数调用开始', {
156
+ ctxId: context?.ctxId,
157
+ eventID: context?.eventID,
158
+ timestamp: new Date().toISOString(),
159
+ });
160
+
161
+ const query = (event && event.params) || {};
162
+ const { contentType, limit = '10' } = query;
163
+
164
+ console.log('[textLogs] 查询参数', { contentType, limit, totalLogs: TEXT_LOGS.length });
165
+
166
+ let logs = TEXT_LOGS;
167
+
168
+ // 模拟数据库查询:按内容类型过滤
169
+ if (contentType) {
170
+ logs = TEXT_LOGS.filter(l => l.contentType === contentType);
171
+ console.log('[textLogs] 按内容类型过滤', { contentType, filteredCount: logs.length });
172
+ }
173
+
174
+ // 限制返回数量
175
+ const limitNum = parseInt(limit) || 10;
176
+ logs = logs.slice(-limitNum).reverse(); // 返回最新的
177
+
178
+ console.log('[textLogs] 查询结果', { total: TEXT_LOGS.length, returned: logs.length });
179
+
180
+ return {
181
+ ok: true,
182
+ code: 0,
183
+ message: "TEXT_LOGS_OK",
184
+ data: {
185
+ total: TEXT_LOGS.length,
186
+ returned: logs.length,
187
+ logs: logs.map(l => ({
188
+ id: l.id,
189
+ contentType: l.contentType,
190
+ preview: l.textContent.substring(0, 100),
191
+ wordCount: l.wordCount,
192
+ charCount: l.charCount,
193
+ submittedAt: l.submittedAt,
194
+ })),
195
+ },
196
+ contentType: "text/plain",
197
+ meta: {
198
+ ctxId: context.ctxId,
199
+ eventID: context.eventID,
200
+ eventType: context.eventType,
201
+ },
202
+ };
203
+ };
204
+
205
+ /**
206
+ * POST 请求:处理 HTML 内容
207
+ *
208
+ * 示例:
209
+ * - POST /text/html
210
+ * - Content-Type: text/html
211
+ * - Body: "<html><body><h1>Hello</h1></body></html>"
212
+ */
213
+ exports.textHtml = async function textHtml(event, context) {
214
+ console.log('[textHtml] 函数调用开始', {
215
+ ctxId: context?.ctxId,
216
+ eventID: context?.eventID,
217
+ timestamp: new Date().toISOString(),
218
+ });
219
+
220
+ // 对齐抖音云托管:HTML 内容从 event.params 中获取(string 或 object)
221
+ let htmlContent = '';
222
+
223
+ const params = event?.params;
224
+
225
+ if (typeof params === 'string') {
226
+ htmlContent = params;
227
+ console.log('[textHtml] 数据格式:event.params 是字符串');
228
+ } else if (params && typeof params.html === 'string') {
229
+ htmlContent = params.html;
230
+ console.log('[textHtml] 数据格式:event.params.html 是字符串');
231
+ } else {
232
+ console.log('[textHtml] 错误:无法解析 HTML 数据格式');
233
+ return {
234
+ ok: false,
235
+ code: 400,
236
+ message: "INVALID_HTML_DATA",
237
+ detail: "无法解析 HTML 数据",
238
+ };
239
+ }
240
+
241
+ console.log('[textHtml] HTML 内容长度', { length: htmlContent.length });
242
+
243
+ // 简单的 HTML 解析(提取标题、链接等)
244
+ const titleMatch = htmlContent.match(/<title[^>]*>([^<]+)<\/title>/i);
245
+ const title = titleMatch ? titleMatch[1] : null;
246
+
247
+ const linkMatches = htmlContent.match(/<a[^>]+href=["']([^"']+)["'][^>]*>/gi) || [];
248
+ const links = linkMatches.map(m => {
249
+ const hrefMatch = m.match(/href=["']([^"']+)["']/i);
250
+ return hrefMatch ? hrefMatch[1] : null;
251
+ }).filter(Boolean);
252
+
253
+ console.log('[textHtml] HTML 解析结果', {
254
+ hasTitle: !!title,
255
+ linkCount: links.length,
256
+ title: title || '未找到标题',
257
+ });
258
+
259
+ return {
260
+ ok: true,
261
+ code: 0,
262
+ message: "TEXT_HTML_OK",
263
+ data: {
264
+ title,
265
+ linkCount: links.length,
266
+ links: links.slice(0, 10), // 只返回前10个链接
267
+ contentLength: htmlContent.length,
268
+ },
269
+ contentType: "text/html",
270
+ meta: {
271
+ ctxId: context.ctxId,
272
+ eventID: context.eventID,
273
+ eventType: context.eventType,
274
+ },
275
+ };
276
+ };
277
+
278
+ /**
279
+ * 测试函数:返回 event 和 context 的结构
280
+ * 用于验证 event 和 context 的结构是否正确
281
+ *
282
+ * 示例:
283
+ * - POST /text/test-structure
284
+ * - Body: { "hello": "dycloud" }
285
+ */
286
+ exports.textTestStructure = async function textTestStructure(event, context) {
287
+ // 返回 event 和 context 的结构信息,用于测试验证
288
+ return {
289
+ ok: true,
290
+ code: 0,
291
+ message: "STRUCTURE_TEST_OK",
292
+ data: {
293
+ // event 结构
294
+ event: {
295
+ params: event?.params ?? null,
296
+ // 注意:对齐抖音云托管,用户函数入参只保证 { params }
297
+ },
298
+ // context 结构
299
+ context: {
300
+ ctxId: context?.ctxId,
301
+ eventID: context?.eventID,
302
+ eventType: context?.eventType,
303
+ timestamp: context?.timestamp,
304
+ httpContext: context?.httpContext ? {
305
+ url: context.httpContext.url,
306
+ httpMethod: context.httpContext.httpMethod,
307
+ headers: context.httpContext.headers,
308
+ } : null,
309
+ baseUrl: context?.baseUrl,
310
+ // 注意:request, logger, sse 等不应该被序列化
311
+ },
312
+ },
313
+ meta: {
314
+ ctxId: context.ctxId,
315
+ eventID: context.eventID,
316
+ eventType: context.eventType,
317
+ },
318
+ };
319
+ };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * 用户相关函数示例
3
+ *
4
+ * 保留原有的 userProfile 函数,并添加更多示例
5
+ */
6
+
7
+ // 测试用用户数据
8
+ const USERS = [
9
+ {
10
+ id: "u10001",
11
+ name: "Alice",
12
+ level: "gold",
13
+ maxBorrow: 10,
14
+ },
15
+ {
16
+ id: "u10002",
17
+ name: "Bob",
18
+ level: "silver",
19
+ maxBorrow: 5,
20
+ },
21
+ ];
22
+
23
+ /**
24
+ * 查询用户基本信息
25
+ *
26
+ * 示例:
27
+ * - 请求:POST /user/profile { "userId": "u10001" }
28
+ * - 响应:返回用户的基础信息与一些统计字段
29
+ */
30
+ exports.userProfile = async function userProfile(event, context) {
31
+ console.log('[userProfile] 函数调用开始', {
32
+ ctxId: context?.ctxId,
33
+ eventID: context?.eventID,
34
+ timestamp: new Date().toISOString(),
35
+ });
36
+
37
+ const payload = event?.params || {};
38
+ const userId = payload.userId;
39
+
40
+ console.log('[userProfile] 请求参数', { userId });
41
+
42
+ if (!userId) {
43
+ console.log('[userProfile] 参数验证失败:缺少 userId');
44
+ return {
45
+ ok: false,
46
+ code: 400,
47
+ message: "MISSING_USER_ID",
48
+ detail: "userId 为必填参数",
49
+ };
50
+ }
51
+
52
+ const user = USERS.find((u) => u.id === userId);
53
+ if (!user) {
54
+ console.log('[userProfile] 用户未找到', { userId });
55
+ return {
56
+ ok: false,
57
+ code: 404,
58
+ message: "USER_NOT_FOUND",
59
+ detail: `未找到指定用户: ${userId}`,
60
+ };
61
+ }
62
+
63
+ console.log('[userProfile] 查询成功', {
64
+ userId: user.id,
65
+ userName: user.name,
66
+ userLevel: user.level,
67
+ });
68
+
69
+ return {
70
+ ok: true,
71
+ code: 0,
72
+ message: "USER_PROFILE_OK",
73
+ user: {
74
+ ...user,
75
+ },
76
+ meta: {
77
+ ctxId: context.ctxId,
78
+ eventID: context.eventID,
79
+ eventType: context.eventType,
80
+ },
81
+ };
82
+ };
@@ -1,5 +1,5 @@
1
1
  {
2
- "agentId": "xhs1234567890",
2
+ "agentId": "[从开放平台获取]",
3
3
  "version": "0.0.1",
4
- "desc": "通用智能体 0.0.1"
4
+ "desc": "[从开放平台获取]"
5
5
  }
@@ -0,0 +1,2 @@
1
+ # key
2
+ GAODE_APPID=123
@@ -0,0 +1,17 @@
1
+ {
2
+ "functionsRoot": "./src",
3
+ "functions": [
4
+ {
5
+ "name": "main",
6
+ "directory": "./",
7
+ "source": "index.js",
8
+ "triggerPath": "/"
9
+ },
10
+ {
11
+ "name": "echo",
12
+ "directory": "./",
13
+ "source": "echo.js",
14
+ "triggerPath": "/echo"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "description": "智能体模板",
4
+ "scripts": {
5
+ "dev": "rcb-ff"
6
+ },
7
+ "dependencies": {
8
+ "@vectorx/agent-runtime": "latest",
9
+ "@vectorx/functions-framework": "latest"
10
+ }
11
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "agentId": "xhs1234567890",
3
+ "version": "0.0.1",
4
+ "desc": "通用智能体 0.0.1"
5
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 云托管模板示例:Echo 函数
3
+ *
4
+ * 对应配置:
5
+ * {
6
+ * "name": "echo",
7
+ * "directory": "./",
8
+ * "source": "echo.js",
9
+ * "triggerPath": "/echo"
10
+ * }
11
+ *
12
+ * - 请求入口:POST /echo
13
+ * - 行为:原样返回请求体,并附带简单的 meta 信息
14
+ */
15
+ exports.echo = async function echo(event, context) {
16
+ return {
17
+ message: "Echo from cloudfunction-template",
18
+ input: event || {},
19
+ meta: {
20
+ ctxId: context.ctxId,
21
+ eventID: context.eventID,
22
+ eventType: context.eventType,
23
+ },
24
+ };
25
+ };
26
+
27
+
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 云托管模板示例:默认入口函数
3
+ *
4
+ * 对应配置:
5
+ * {
6
+ * "name": "main",
7
+ * "directory": "./",
8
+ * "source": "index.js",
9
+ * "triggerPath": "/"
10
+ * }
11
+ *
12
+ * - 请求入口:POST / (参见 agent-cloudbase-functions.json 中的 triggerPath)
13
+ * - 参数:HTTP 请求体会被解析为 JSON 传入 event
14
+ * - 返回:对象会被直接作为 HTTP 响应 Body
15
+ */
16
+ exports.main = async function main(event, context) {
17
+ // event 为解析后的请求体,context 为运行上下文(含请求信息、日志、请求工具等)
18
+ const now = new Date().toISOString();
19
+
20
+ return {
21
+ message: "Hello from cloudfunction-template 'main' function 🎯",
22
+ timestamp: now,
23
+ // 将用户请求原样回显,方便本地调试
24
+ input: event || {},
25
+ // 仅保留一些常用的上下文字段示例
26
+ context: {
27
+ ctxId: context.ctxId,
28
+ eventID: context.eventID,
29
+ eventType: context.eventType,
30
+ },
31
+ };
32
+ };
33
+
34
+