@ynhcj/xiaoyi-channel 0.0.13-beta → 0.0.15-beta
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.
|
@@ -80,6 +80,17 @@ export const searchCalendarTool = {
|
|
|
80
80
|
const date = new Date(year, month, day, hours, minutes, seconds);
|
|
81
81
|
return date.getTime();
|
|
82
82
|
};
|
|
83
|
+
// Helper function to convert timestamp to YYYYMMDD hhmmss format
|
|
84
|
+
const formatTimestamp = (timestamp) => {
|
|
85
|
+
const date = new Date(timestamp);
|
|
86
|
+
const year = date.getFullYear();
|
|
87
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
88
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
89
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
90
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
91
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
92
|
+
return `${year}${month}${day} ${hours}${minutes}${seconds}`;
|
|
93
|
+
};
|
|
83
94
|
let startTimeMs;
|
|
84
95
|
let endTimeMs;
|
|
85
96
|
try {
|
|
@@ -190,6 +201,22 @@ export const searchCalendarTool = {
|
|
|
190
201
|
if (result === undefined) {
|
|
191
202
|
logger.warn(`[SEARCH_CALENDAR_TOOL] ⚠️ Result is undefined, returning empty result`);
|
|
192
203
|
}
|
|
204
|
+
// Convert dtStart and dtEnd from timestamps to YYYYMMDD hhmmss format
|
|
205
|
+
if (result && result.items && Array.isArray(result.items)) {
|
|
206
|
+
logger.log(`[SEARCH_CALENDAR_TOOL] 🔄 Converting timestamps to formatted dates...`);
|
|
207
|
+
result.items = result.items.map((item) => {
|
|
208
|
+
const formattedItem = { ...item };
|
|
209
|
+
if (item.dtStart) {
|
|
210
|
+
formattedItem.dtStart = formatTimestamp(item.dtStart);
|
|
211
|
+
logger.log(`[SEARCH_CALENDAR_TOOL] - dtStart: ${item.dtStart} -> ${formattedItem.dtStart}`);
|
|
212
|
+
}
|
|
213
|
+
if (item.dtEnd) {
|
|
214
|
+
formattedItem.dtEnd = formatTimestamp(item.dtEnd);
|
|
215
|
+
logger.log(`[SEARCH_CALENDAR_TOOL] - dtEnd: ${item.dtEnd} -> ${formattedItem.dtEnd}`);
|
|
216
|
+
}
|
|
217
|
+
return formattedItem;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
193
220
|
resolve({
|
|
194
221
|
content: [
|
|
195
222
|
{
|
|
@@ -13,18 +13,14 @@ import { logger } from "../utils/logger.js";
|
|
|
13
13
|
export const uploadPhotoTool = {
|
|
14
14
|
name: "upload_photo",
|
|
15
15
|
label: "Upload Photo",
|
|
16
|
-
description: "将手机本地照片回传并获取可公网访问的 URL。使用前必须先调用 search_photo_gallery 工具获取照片的 mediaUri。参数说明:mediaUris 是照片在手机本地的 URI
|
|
16
|
+
description: "将手机本地照片回传并获取可公网访问的 URL。使用前必须先调用 search_photo_gallery 工具获取照片的 mediaUri。参数说明:mediaUris 是照片在手机本地的 URI 数组或 JSON 字符串数组(从 search_photo_gallery 工具获取)。限制:每次最多支持传入 5 条 mediaUri。操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。",
|
|
17
17
|
parameters: {
|
|
18
18
|
type: "object",
|
|
19
19
|
properties: {
|
|
20
20
|
mediaUris: {
|
|
21
|
-
type
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
25
|
-
description: "照片在手机本地的 URI 数组,必须先通过 search_photo_gallery 工具获取。每次最多支持 5 条 URI。",
|
|
26
|
-
maxItems: 5,
|
|
27
|
-
minItems: 1,
|
|
21
|
+
// 不指定 type,允许传入数组或 JSON 字符串
|
|
22
|
+
// 具体的类型验证和转换在 execute 函数内部进行
|
|
23
|
+
description: "照片在手机本地的 URI 数组(或 JSON 字符串形式的数组),必须先通过 search_photo_gallery 工具获取。每次最多支持 5 条 URI。支持传入数组 [\"uri1\", \"uri2\"] 或 JSON 字符串 '[\"uri1\", \"uri2\"]'。",
|
|
28
24
|
},
|
|
29
25
|
},
|
|
30
26
|
required: ["mediaUris"],
|
|
@@ -32,19 +28,56 @@ export const uploadPhotoTool = {
|
|
|
32
28
|
async execute(toolCallId, params) {
|
|
33
29
|
logger.log(`[UPLOAD_PHOTO_TOOL] 🚀 Starting execution`);
|
|
34
30
|
logger.log(`[UPLOAD_PHOTO_TOOL] - toolCallId: ${toolCallId}`);
|
|
35
|
-
logger.log(`[UPLOAD_PHOTO_TOOL] - params:`, JSON.stringify(params));
|
|
31
|
+
logger.log(`[UPLOAD_PHOTO_TOOL] - params (raw):`, JSON.stringify(params));
|
|
32
|
+
logger.log(`[UPLOAD_PHOTO_TOOL] - params.mediaUris type:`, typeof params.mediaUris);
|
|
36
33
|
logger.log(`[UPLOAD_PHOTO_TOOL] - timestamp: ${new Date().toISOString()}`);
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
// ===== 参数规范化:兼容数组和 JSON 字符串 =====
|
|
35
|
+
let mediaUris = null;
|
|
36
|
+
if (!params.mediaUris) {
|
|
37
|
+
logger.error(`[UPLOAD_PHOTO_TOOL] ❌ Missing parameter: mediaUris`);
|
|
38
|
+
throw new Error("Missing required parameter: mediaUris");
|
|
39
|
+
}
|
|
40
|
+
// 情况1: 已经是数组
|
|
41
|
+
if (Array.isArray(params.mediaUris)) {
|
|
42
|
+
logger.log(`[UPLOAD_PHOTO_TOOL] ✅ mediaUris is already an array`);
|
|
43
|
+
mediaUris = params.mediaUris;
|
|
44
|
+
}
|
|
45
|
+
// 情况2: 是字符串,尝试解析为 JSON 数组
|
|
46
|
+
else if (typeof params.mediaUris === 'string') {
|
|
47
|
+
logger.log(`[UPLOAD_PHOTO_TOOL] 🔄 mediaUris is a string, attempting to parse as JSON...`);
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(params.mediaUris);
|
|
50
|
+
if (Array.isArray(parsed)) {
|
|
51
|
+
logger.log(`[UPLOAD_PHOTO_TOOL] ✅ Successfully parsed JSON string to array`);
|
|
52
|
+
mediaUris = parsed;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
logger.error(`[UPLOAD_PHOTO_TOOL] ❌ Parsed JSON is not an array:`, typeof parsed);
|
|
56
|
+
throw new Error("mediaUris must be an array or a JSON string representing an array");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (parseError) {
|
|
60
|
+
logger.error(`[UPLOAD_PHOTO_TOOL] ❌ Failed to parse mediaUris as JSON:`, parseError);
|
|
61
|
+
throw new Error(`mediaUris must be a valid JSON array string. Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// 情况3: 其他类型,报错
|
|
65
|
+
else {
|
|
66
|
+
logger.error(`[UPLOAD_PHOTO_TOOL] ❌ Invalid mediaUris type:`, typeof params.mediaUris);
|
|
67
|
+
throw new Error(`mediaUris must be an array or a JSON string, got ${typeof params.mediaUris}`);
|
|
68
|
+
}
|
|
69
|
+
// 验证数组非空
|
|
70
|
+
if (!mediaUris || mediaUris.length === 0) {
|
|
71
|
+
logger.error(`[UPLOAD_PHOTO_TOOL] ❌ mediaUris array is empty`);
|
|
72
|
+
throw new Error("mediaUris array cannot be empty");
|
|
41
73
|
}
|
|
74
|
+
logger.log(`[UPLOAD_PHOTO_TOOL] ✅ Normalized mediaUris:`, JSON.stringify(mediaUris));
|
|
42
75
|
// Validate maximum 5 URIs
|
|
43
|
-
if (
|
|
44
|
-
logger.error(`[UPLOAD_PHOTO_TOOL] ❌ Too many mediaUris: ${
|
|
45
|
-
throw new Error(`最多支持 5 条 mediaUri,当前提供了 ${
|
|
76
|
+
if (mediaUris.length > 5) {
|
|
77
|
+
logger.error(`[UPLOAD_PHOTO_TOOL] ❌ Too many mediaUris: ${mediaUris.length}`);
|
|
78
|
+
throw new Error(`最多支持 5 条 mediaUri,当前提供了 ${mediaUris.length} 条。请分批处理。`);
|
|
46
79
|
}
|
|
47
|
-
logger.log(`[UPLOAD_PHOTO_TOOL] - mediaUris count: ${
|
|
80
|
+
logger.log(`[UPLOAD_PHOTO_TOOL] - mediaUris count: ${mediaUris.length}`);
|
|
48
81
|
// Get session context
|
|
49
82
|
logger.log(`[UPLOAD_PHOTO_TOOL] 🔍 Attempting to get session context...`);
|
|
50
83
|
const sessionContext = getLatestSessionContext();
|
|
@@ -64,7 +97,7 @@ export const uploadPhotoTool = {
|
|
|
64
97
|
logger.log(`[UPLOAD_PHOTO_TOOL] ✅ WebSocket manager obtained`);
|
|
65
98
|
// Get public URLs for the photos
|
|
66
99
|
logger.log(`[UPLOAD_PHOTO_TOOL] 🌐 Getting public URLs for photos...`);
|
|
67
|
-
const imageUrls = await getPhotoUrls(wsManager, config, sessionId, taskId, messageId,
|
|
100
|
+
const imageUrls = await getPhotoUrls(wsManager, config, sessionId, taskId, messageId, mediaUris);
|
|
68
101
|
logger.log(`[UPLOAD_PHOTO_TOOL] 🎉 Successfully retrieved ${imageUrls.length} photo URLs`);
|
|
69
102
|
return {
|
|
70
103
|
content: [
|