@ynhcj/xiaoyi-channel 0.0.51-beta → 0.0.52-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.
- package/dist/src/bot.js +0 -16
- package/dist/src/client.js +0 -2
- package/dist/src/formatter.js +3 -23
- package/dist/src/heartbeat.js +0 -1
- package/dist/src/reply-dispatcher.js +32 -0
- package/dist/src/tools/calendar-tool.js +2 -37
- package/dist/src/tools/call-phone-tool.js +1 -42
- package/dist/src/tools/create-alarm-tool.js +3 -74
- package/dist/src/tools/delete-alarm-tool.js +3 -45
- package/dist/src/tools/image-reading-tool.js +0 -47
- package/dist/src/tools/location-tool.js +1 -32
- package/dist/src/tools/modify-alarm-tool.js +3 -77
- package/dist/src/tools/modify-note-tool.js +1 -34
- package/dist/src/tools/note-tool.js +2 -4
- package/dist/src/tools/search-alarm-tool.js +3 -61
- package/dist/src/tools/search-calendar-tool.js +2 -39
- package/dist/src/tools/search-contact-tool.js +0 -30
- package/dist/src/tools/search-file-tool.js +0 -33
- package/dist/src/tools/search-message-tool.js +0 -33
- package/dist/src/tools/search-note-tool.js +1 -26
- package/dist/src/tools/search-photo-gallery-tool.js +2 -31
- package/dist/src/tools/send-file-to-user-tool.js +0 -39
- package/dist/src/tools/send-message-tool.js +1 -39
- package/dist/src/tools/session-manager.js +0 -45
- package/dist/src/tools/upload-file-tool.js +0 -49
- package/dist/src/tools/upload-photo-tool.js +0 -42
- package/dist/src/tools/view-push-result-tool.js +0 -11
- package/dist/src/tools/xiaoyi-collection-tool.js +4 -82
- package/dist/src/tools/xiaoyi-gui-tool.js +0 -34
- package/dist/src/websocket.js +24 -8
- package/package.json +1 -1
package/dist/src/bot.js
CHANGED
|
@@ -336,19 +336,3 @@ function buildXYMediaPayload(mediaList) {
|
|
|
336
336
|
MediaTypes: mediaTypes.length > 0 ? mediaTypes : undefined,
|
|
337
337
|
};
|
|
338
338
|
}
|
|
339
|
-
/**
|
|
340
|
-
* Infer OpenClaw media type from file type string.
|
|
341
|
-
*/
|
|
342
|
-
function inferMediaType(fileType) {
|
|
343
|
-
const lower = fileType.toLowerCase();
|
|
344
|
-
if (lower.includes("image") || /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(lower)) {
|
|
345
|
-
return "image";
|
|
346
|
-
}
|
|
347
|
-
if (lower.includes("video") || /\.(mp4|avi|mov|mkv|webm)$/i.test(lower)) {
|
|
348
|
-
return "video";
|
|
349
|
-
}
|
|
350
|
-
if (lower.includes("audio") || /\.(mp3|wav|ogg|m4a)$/i.test(lower)) {
|
|
351
|
-
return "audio";
|
|
352
|
-
}
|
|
353
|
-
return "file";
|
|
354
|
-
}
|
package/dist/src/client.js
CHANGED
|
@@ -85,8 +85,6 @@ export function diagnoseAllManagers() {
|
|
|
85
85
|
let orphanCount = 0;
|
|
86
86
|
wsManagerCache.forEach((manager, key) => {
|
|
87
87
|
const diag = manager.getConnectionDiagnostics();
|
|
88
|
-
console.log(`📌 Manager: ${key}`);
|
|
89
|
-
console.log(` Shutting down: ${diag.isShuttingDown}`);
|
|
90
88
|
console.log(` Total event listeners on manager: ${diag.totalEventListeners}`);
|
|
91
89
|
// Connection
|
|
92
90
|
console.log(` 🔌 Connection:`);
|
package/dist/src/formatter.js
CHANGED
|
@@ -52,18 +52,11 @@ export async function sendA2AResponse(params) {
|
|
|
52
52
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
53
53
|
};
|
|
54
54
|
// 📋 Log complete response body
|
|
55
|
-
log(`[A2A_RESPONSE] 📤 Sending A2A artifact-update response
|
|
56
|
-
log(`[A2A_RESPONSE] - sessionId: ${sessionId}`);
|
|
57
|
-
log(`[A2A_RESPONSE] - taskId: ${taskId}`);
|
|
58
|
-
log(`[A2A_RESPONSE] - messageId: ${messageId}`);
|
|
55
|
+
log(`[A2A_RESPONSE] 📤 Sending A2A artifact-update response: taskId: ${taskId}`);
|
|
59
56
|
log(`[A2A_RESPONSE] - append: ${append}`);
|
|
60
57
|
log(`[A2A_RESPONSE] - final: ${final}`);
|
|
61
|
-
log(`[A2A_RESPONSE] - text
|
|
58
|
+
log(`[A2A_RESPONSE] - text: ${text}`);
|
|
62
59
|
log(`[A2A_RESPONSE] - files count: ${files?.length ?? 0}`);
|
|
63
|
-
log(`[A2A_RESPONSE] 📦 Complete outbound message:`);
|
|
64
|
-
log(JSON.stringify(outboundMessage, null, 2));
|
|
65
|
-
log(`[A2A_RESPONSE] 📦 JSON-RPC response body:`);
|
|
66
|
-
log(JSON.stringify(jsonRpcResponse, null, 2));
|
|
67
60
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
68
61
|
log(`[A2A_RESPONSE] ✅ Message sent successfully`);
|
|
69
62
|
}
|
|
@@ -152,15 +145,10 @@ export async function sendStatusUpdate(params) {
|
|
|
152
145
|
};
|
|
153
146
|
// 📋 Log complete response body
|
|
154
147
|
log(`[A2A_STATUS] 📤 Sending A2A status-update:`);
|
|
155
|
-
log(`[A2A_STATUS] - sessionId: ${sessionId}`);
|
|
156
148
|
log(`[A2A_STATUS] - taskId: ${taskId}`);
|
|
157
149
|
log(`[A2A_STATUS] - messageId: ${messageId}`);
|
|
158
150
|
log(`[A2A_STATUS] - state: ${state}`);
|
|
159
151
|
log(`[A2A_STATUS] - text: "${text}"`);
|
|
160
|
-
log(`[A2A_STATUS] 📦 Complete outbound message:`);
|
|
161
|
-
log(JSON.stringify(outboundMessage, null, 2));
|
|
162
|
-
log(`[A2A_STATUS] 📦 JSON-RPC response body:`);
|
|
163
|
-
log(JSON.stringify(jsonRpcResponse, null, 2));
|
|
164
152
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
165
153
|
log(`[A2A_STATUS] ✅ Status update sent successfully`);
|
|
166
154
|
}
|
|
@@ -208,15 +196,7 @@ export async function sendCommand(params) {
|
|
|
208
196
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
209
197
|
};
|
|
210
198
|
// 📋 Log complete response body
|
|
211
|
-
log(`[A2A_COMMAND] 📤 Sending A2A command
|
|
212
|
-
log(`[A2A_COMMAND] - sessionId: ${sessionId}`);
|
|
213
|
-
log(`[A2A_COMMAND] - taskId: ${taskId}`);
|
|
214
|
-
log(`[A2A_COMMAND] - messageId: ${messageId}`);
|
|
215
|
-
log(`[A2A_COMMAND] - command: ${command.header.namespace}::${command.header.name}`);
|
|
216
|
-
log(`[A2A_COMMAND] 📦 Complete outbound message:`);
|
|
217
|
-
log(JSON.stringify(outboundMessage, null, 2));
|
|
218
|
-
log(`[A2A_COMMAND] 📦 JSON-RPC response body:`);
|
|
219
|
-
log(JSON.stringify(jsonRpcResponse, null, 2));
|
|
199
|
+
log(`[A2A_COMMAND] 📤 Sending A2A command: taskId: ${taskId}`);
|
|
220
200
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
221
201
|
log(`[A2A_COMMAND] ✅ Command sent successfully`);
|
|
222
202
|
}
|
package/dist/src/heartbeat.js
CHANGED
|
@@ -80,7 +80,6 @@ export class HeartbeatManager {
|
|
|
80
80
|
this.error(`Heartbeat timeout for ${this.serverName}`);
|
|
81
81
|
this.onTimeout();
|
|
82
82
|
}, this.config.timeout);
|
|
83
|
-
this.log(`[DEBUG] Heartbeat sent for ${this.serverName}`);
|
|
84
83
|
}
|
|
85
84
|
catch (error) {
|
|
86
85
|
this.error(`Failed to send heartbeat for ${this.serverName}:`, error);
|
|
@@ -3,6 +3,37 @@ import { getXYRuntime } from "./runtime.js";
|
|
|
3
3
|
import { sendA2AResponse, sendStatusUpdate, sendReasoningTextUpdate } from "./formatter.js";
|
|
4
4
|
import { resolveXYConfig } from "./config.js";
|
|
5
5
|
import { getCurrentTaskId, getCurrentMessageId } from "./task-manager.js";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import path from "path";
|
|
8
|
+
/**
|
|
9
|
+
* 清理 /tmp/xy_channel 目录中的所有文件
|
|
10
|
+
*/
|
|
11
|
+
async function cleanupTempDir(tempDir = "/tmp/xy_channel") {
|
|
12
|
+
try {
|
|
13
|
+
const stats = await fs.stat(tempDir).catch(() => null);
|
|
14
|
+
if (!stats?.isDirectory()) {
|
|
15
|
+
return; // 目录不存在,直接返回
|
|
16
|
+
}
|
|
17
|
+
const files = await fs.readdir(tempDir);
|
|
18
|
+
let cleanedCount = 0;
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
const filePath = path.join(tempDir, file);
|
|
21
|
+
try {
|
|
22
|
+
await fs.unlink(filePath);
|
|
23
|
+
cleanedCount++;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
// 忽略单个文件删除失败,继续处理其他文件
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (cleanedCount > 0) {
|
|
30
|
+
console.log(`[CLEANUP] 🧹 Cleaned ${cleanedCount} files from ${tempDir}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error(`[CLEANUP] ❌ Failed to cleanup temp dir:`, err);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
6
37
|
/**
|
|
7
38
|
* Create a reply dispatcher for XY channel messages.
|
|
8
39
|
* Follows feishu pattern with status updates and streaming support.
|
|
@@ -206,6 +237,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
206
237
|
}
|
|
207
238
|
}
|
|
208
239
|
stopStatusInterval();
|
|
240
|
+
void cleanupTempDir();
|
|
209
241
|
},
|
|
210
242
|
onCleanup: () => {
|
|
211
243
|
const currentTaskId = getActiveTaskId();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getXYWebSocketManager } from "../client.js";
|
|
2
2
|
import { sendCommand } from "../formatter.js";
|
|
3
3
|
import { getCurrentSessionContext } from "./session-manager.js";
|
|
4
|
-
import { logger } from "../utils/logger.js";
|
|
5
4
|
/**
|
|
6
5
|
* XY calendar event tool - creates a calendar event on user's device.
|
|
7
6
|
* Requires title, dtStart (start time), and dtEnd (end time) parameters.
|
|
@@ -12,6 +11,8 @@ export const calendarTool = {
|
|
|
12
11
|
label: "Create Calendar Event",
|
|
13
12
|
description: `在用户设备上创建日程。需要提供日程标题、开始时间和结束时间。时间格式必须为:yyyy-mm-dd hh:mm:ss(例如:2024-01-15 14:30:00)。注意:该工具执行时间较长(最多60秒),请勿重复调用,超时或失败时最多重试一次。
|
|
14
13
|
注意事项:使用该工具之前需获取当前真实时间
|
|
14
|
+
|
|
15
|
+
回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。
|
|
15
16
|
`,
|
|
16
17
|
parameters: {
|
|
17
18
|
type: "object",
|
|
@@ -32,47 +33,25 @@ export const calendarTool = {
|
|
|
32
33
|
required: ["title", "dtStart", "dtEnd"],
|
|
33
34
|
},
|
|
34
35
|
async execute(toolCallId, params) {
|
|
35
|
-
logger.log(`[CALENDAR_TOOL] 🚀 Starting execution`);
|
|
36
|
-
logger.log(`[CALENDAR_TOOL] - toolCallId: ${toolCallId}`);
|
|
37
|
-
logger.log(`[CALENDAR_TOOL] - params:`, JSON.stringify(params));
|
|
38
|
-
logger.log(`[CALENDAR_TOOL] - timestamp: ${new Date().toISOString()}`);
|
|
39
36
|
// Validate parameters
|
|
40
37
|
if (!params.title || !params.dtStart || !params.dtEnd) {
|
|
41
|
-
logger.error(`[CALENDAR_TOOL] ❌ Missing required parameters`);
|
|
42
38
|
throw new Error("Missing required parameters: title, dtStart, and dtEnd are required");
|
|
43
39
|
}
|
|
44
40
|
// Convert time strings to millisecond timestamps
|
|
45
|
-
logger.log(`[CALENDAR_TOOL] 🕒 Converting time strings to timestamps...`);
|
|
46
|
-
logger.log(`[CALENDAR_TOOL] - dtStart input: ${params.dtStart}`);
|
|
47
|
-
logger.log(`[CALENDAR_TOOL] - dtEnd input: ${params.dtEnd}`);
|
|
48
41
|
const dtStartMs = new Date(params.dtStart).getTime();
|
|
49
42
|
const dtEndMs = new Date(params.dtEnd).getTime();
|
|
50
43
|
if (isNaN(dtStartMs) || isNaN(dtEndMs)) {
|
|
51
|
-
logger.error(`[CALENDAR_TOOL] ❌ Invalid time format`);
|
|
52
44
|
throw new Error("Invalid time format. Required format: yyyy-mm-dd hh:mm:ss (e.g., 2024-01-15 14:30:00)");
|
|
53
45
|
}
|
|
54
|
-
logger.log(`[CALENDAR_TOOL] ✅ Time conversion successful`);
|
|
55
|
-
logger.log(`[CALENDAR_TOOL] - dtStart timestamp: ${dtStartMs}`);
|
|
56
|
-
logger.log(`[CALENDAR_TOOL] - dtEnd timestamp: ${dtEndMs}`);
|
|
57
46
|
// Get session context
|
|
58
|
-
logger.log(`[CALENDAR_TOOL] 🔍 Attempting to get session context...`);
|
|
59
47
|
const sessionContext = getCurrentSessionContext();
|
|
60
48
|
if (!sessionContext) {
|
|
61
|
-
logger.error(`[CALENDAR_TOOL] ❌ FAILED: No active session found!`);
|
|
62
|
-
logger.error(`[CALENDAR_TOOL] - toolCallId: ${toolCallId}`);
|
|
63
49
|
throw new Error("No active XY session found. Calendar tool can only be used during an active conversation.");
|
|
64
50
|
}
|
|
65
|
-
logger.log(`[CALENDAR_TOOL] ✅ Session context found`);
|
|
66
|
-
logger.log(`[CALENDAR_TOOL] - sessionId: ${sessionContext.sessionId}`);
|
|
67
|
-
logger.log(`[CALENDAR_TOOL] - taskId: ${sessionContext.taskId}`);
|
|
68
|
-
logger.log(`[CALENDAR_TOOL] - messageId: ${sessionContext.messageId}`);
|
|
69
51
|
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
70
52
|
// Get WebSocket manager
|
|
71
|
-
logger.log(`[CALENDAR_TOOL] 🔌 Getting WebSocket manager...`);
|
|
72
53
|
const wsManager = getXYWebSocketManager(config);
|
|
73
|
-
logger.log(`[CALENDAR_TOOL] ✅ WebSocket manager obtained`);
|
|
74
54
|
// Build CreateCalendarEvent command
|
|
75
|
-
logger.log(`[CALENDAR_TOOL] 📦 Building CreateCalendarEvent command...`);
|
|
76
55
|
const command = {
|
|
77
56
|
header: {
|
|
78
57
|
namespace: "Common",
|
|
@@ -108,25 +87,17 @@ export const calendarTool = {
|
|
|
108
87
|
},
|
|
109
88
|
};
|
|
110
89
|
// Send command and wait for response (60 second timeout)
|
|
111
|
-
logger.log(`[CALENDAR_TOOL] ⏳ Setting up promise to wait for calendar event response...`);
|
|
112
|
-
logger.log(`[CALENDAR_TOOL] - Timeout: 60 seconds`);
|
|
113
90
|
return new Promise((resolve, reject) => {
|
|
114
91
|
const timeout = setTimeout(() => {
|
|
115
|
-
logger.error(`[CALENDAR_TOOL] ⏰ Timeout: No response received within 60 seconds`);
|
|
116
92
|
wsManager.off("data-event", handler);
|
|
117
93
|
reject(new Error("创建日程超时(60秒)"));
|
|
118
94
|
}, 60000);
|
|
119
95
|
// Listen for data events from WebSocket
|
|
120
96
|
const handler = (event) => {
|
|
121
|
-
logger.log(`[CALENDAR_TOOL] 📨 Received data event:`, JSON.stringify(event));
|
|
122
97
|
if (event.intentName === "CreateCalendarEvent") {
|
|
123
|
-
logger.log(`[CALENDAR_TOOL] 🎯 CreateCalendarEvent event received`);
|
|
124
|
-
logger.log(`[CALENDAR_TOOL] - status: ${event.status}`);
|
|
125
98
|
clearTimeout(timeout);
|
|
126
99
|
wsManager.off("data-event", handler);
|
|
127
100
|
if (event.status === "success" && event.outputs) {
|
|
128
|
-
logger.log(`[CALENDAR_TOOL] ✅ Calendar event created successfully`);
|
|
129
|
-
logger.log(`[CALENDAR_TOOL] - outputs:`, JSON.stringify(event.outputs));
|
|
130
101
|
resolve({
|
|
131
102
|
content: [
|
|
132
103
|
{
|
|
@@ -137,17 +108,13 @@ export const calendarTool = {
|
|
|
137
108
|
});
|
|
138
109
|
}
|
|
139
110
|
else {
|
|
140
|
-
logger.error(`[CALENDAR_TOOL] ❌ Calendar event creation failed`);
|
|
141
|
-
logger.error(`[CALENDAR_TOOL] - status: ${event.status}`);
|
|
142
111
|
reject(new Error(`创建日程失败: ${event.status}`));
|
|
143
112
|
}
|
|
144
113
|
}
|
|
145
114
|
};
|
|
146
115
|
// Register event handler
|
|
147
|
-
logger.log(`[CALENDAR_TOOL] 📡 Registering data-event handler on WebSocket manager`);
|
|
148
116
|
wsManager.on("data-event", handler);
|
|
149
117
|
// Send the command
|
|
150
|
-
logger.log(`[CALENDAR_TOOL] 📤 Sending CreateCalendarEvent command...`);
|
|
151
118
|
sendCommand({
|
|
152
119
|
config,
|
|
153
120
|
sessionId,
|
|
@@ -156,10 +123,8 @@ export const calendarTool = {
|
|
|
156
123
|
command,
|
|
157
124
|
})
|
|
158
125
|
.then(() => {
|
|
159
|
-
logger.log(`[CALENDAR_TOOL] ✅ Command sent successfully, waiting for response...`);
|
|
160
126
|
})
|
|
161
127
|
.catch((error) => {
|
|
162
|
-
logger.error(`[CALENDAR_TOOL] ❌ Failed to send command:`, error);
|
|
163
128
|
clearTimeout(timeout);
|
|
164
129
|
wsManager.off("data-event", handler);
|
|
165
130
|
reject(error);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getXYWebSocketManager } from "../client.js";
|
|
2
2
|
import { sendCommand } from "../formatter.js";
|
|
3
3
|
import { getCurrentSessionContext } from "./session-manager.js";
|
|
4
|
-
import { logger } from "../utils/logger.js";
|
|
5
4
|
/**
|
|
6
5
|
* XY call phone tool - makes a phone call on user's device.
|
|
7
6
|
* Requires phoneNumber parameter and optional slotId (0 for primary SIM, 1 for secondary SIM).
|
|
@@ -9,7 +8,7 @@ import { logger } from "../utils/logger.js";
|
|
|
9
8
|
export const callPhoneTool = {
|
|
10
9
|
name: "call_phone",
|
|
11
10
|
label: "Call Phone",
|
|
12
|
-
description: "拨打电话。需要提供要拨打的电话号码。slotId参数可选,默认为0(主卡),如果用户明确要求使用副卡则设置为1。注意:操作超时时间为60
|
|
11
|
+
description: "拨打电话。需要提供要拨打的电话号码。slotId参数可选,默认为0(主卡),如果用户明确要求使用副卡则设置为1。注意:操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。",
|
|
13
12
|
parameters: {
|
|
14
13
|
type: "object",
|
|
15
14
|
properties: {
|
|
@@ -26,43 +25,25 @@ export const callPhoneTool = {
|
|
|
26
25
|
required: ["phoneNumber"],
|
|
27
26
|
},
|
|
28
27
|
async execute(toolCallId, params) {
|
|
29
|
-
logger.log(`[CALL_PHONE_TOOL] 🚀 Starting execution`);
|
|
30
|
-
logger.log(`[CALL_PHONE_TOOL] - toolCallId: ${toolCallId}`);
|
|
31
|
-
logger.log(`[CALL_PHONE_TOOL] - params:`, JSON.stringify(params));
|
|
32
|
-
logger.log(`[CALL_PHONE_TOOL] - timestamp: ${new Date().toISOString()}`);
|
|
33
28
|
// Validate phoneNumber parameter
|
|
34
29
|
if (!params.phoneNumber || typeof params.phoneNumber !== "string" || params.phoneNumber.trim() === "") {
|
|
35
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Missing or invalid phoneNumber parameter`);
|
|
36
30
|
throw new Error("Missing required parameter: phoneNumber must be a non-empty string");
|
|
37
31
|
}
|
|
38
32
|
// Set default slotId if not provided
|
|
39
33
|
const slotId = params.slotId !== undefined && params.slotId !== null ? params.slotId : 0;
|
|
40
34
|
// Validate slotId (must be 0 or 1)
|
|
41
35
|
if (slotId !== 0 && slotId !== 1) {
|
|
42
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Invalid slotId: ${slotId}`);
|
|
43
36
|
throw new Error("Invalid slotId: must be 0 (primary SIM) or 1 (secondary SIM)");
|
|
44
37
|
}
|
|
45
|
-
logger.log(`[CALL_PHONE_TOOL] 📞 Preparing to call phone number: ${params.phoneNumber}`);
|
|
46
|
-
logger.log(`[CALL_PHONE_TOOL] - slotId: ${slotId} (${slotId === 0 ? "主卡" : "副卡"})`);
|
|
47
38
|
// Get session context
|
|
48
|
-
logger.log(`[CALL_PHONE_TOOL] 🔍 Attempting to get session context...`);
|
|
49
39
|
const sessionContext = getCurrentSessionContext();
|
|
50
40
|
if (!sessionContext) {
|
|
51
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ FAILED: No active session found!`);
|
|
52
|
-
logger.error(`[CALL_PHONE_TOOL] - toolCallId: ${toolCallId}`);
|
|
53
41
|
throw new Error("No active XY session found. Call phone tool can only be used during an active conversation.");
|
|
54
42
|
}
|
|
55
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ Session context found`);
|
|
56
|
-
logger.log(`[CALL_PHONE_TOOL] - sessionId: ${sessionContext.sessionId}`);
|
|
57
|
-
logger.log(`[CALL_PHONE_TOOL] - taskId: ${sessionContext.taskId}`);
|
|
58
|
-
logger.log(`[CALL_PHONE_TOOL] - messageId: ${sessionContext.messageId}`);
|
|
59
43
|
const { config, sessionId, taskId, messageId } = sessionContext;
|
|
60
44
|
// Get WebSocket manager
|
|
61
|
-
logger.log(`[CALL_PHONE_TOOL] 🔌 Getting WebSocket manager...`);
|
|
62
45
|
const wsManager = getXYWebSocketManager(config);
|
|
63
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ WebSocket manager obtained`);
|
|
64
46
|
// Build StartCall command
|
|
65
|
-
logger.log(`[CALL_PHONE_TOOL] 📦 Building StartCall command...`);
|
|
66
47
|
const command = {
|
|
67
48
|
header: {
|
|
68
49
|
namespace: "Common",
|
|
@@ -97,34 +78,22 @@ export const callPhoneTool = {
|
|
|
97
78
|
pageControlRelated: false,
|
|
98
79
|
},
|
|
99
80
|
};
|
|
100
|
-
logger.log(`[CALL_PHONE_TOOL] 📋 Command details:`, JSON.stringify(command, null, 2));
|
|
101
81
|
// Send command and wait for response (60 second timeout)
|
|
102
|
-
logger.log(`[CALL_PHONE_TOOL] ⏳ Setting up promise to wait for call response...`);
|
|
103
|
-
logger.log(`[CALL_PHONE_TOOL] - Timeout: 60 seconds`);
|
|
104
82
|
return new Promise((resolve, reject) => {
|
|
105
83
|
const timeout = setTimeout(() => {
|
|
106
|
-
logger.error(`[CALL_PHONE_TOOL] ⏰ Timeout: No response received within 60 seconds`);
|
|
107
84
|
wsManager.off("data-event", handler);
|
|
108
85
|
reject(new Error("拨打电话超时(60秒)"));
|
|
109
86
|
}, 60000);
|
|
110
87
|
// Listen for data events from WebSocket
|
|
111
88
|
const handler = (event) => {
|
|
112
|
-
logger.log(`[CALL_PHONE_TOOL] 📨 Received data event:`, JSON.stringify(event));
|
|
113
89
|
if (event.intentName === "StartCall") {
|
|
114
|
-
logger.log(`[CALL_PHONE_TOOL] 🎯 StartCall event received`);
|
|
115
|
-
logger.log(`[CALL_PHONE_TOOL] - status: ${event.status}`);
|
|
116
90
|
clearTimeout(timeout);
|
|
117
91
|
wsManager.off("data-event", handler);
|
|
118
92
|
if (event.status === "success" && event.outputs) {
|
|
119
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ Call response received`);
|
|
120
|
-
logger.log(`[CALL_PHONE_TOOL] - outputs:`, JSON.stringify(event.outputs));
|
|
121
93
|
// Check for error code in outputs
|
|
122
94
|
const code = event.outputs.code !== undefined ? event.outputs.code : null;
|
|
123
95
|
if (code !== null && code !== 0) {
|
|
124
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Device returned error`);
|
|
125
|
-
logger.error(`[CALL_PHONE_TOOL] - code: ${code}`);
|
|
126
96
|
const errorMsg = event.outputs.errorMsg || event.outputs.errMsg || "未知错误";
|
|
127
|
-
logger.error(`[CALL_PHONE_TOOL] - errorMsg: ${errorMsg}`);
|
|
128
97
|
reject(new Error(`拨打电话失败: ${errorMsg} (错误代码: ${code})`));
|
|
129
98
|
return;
|
|
130
99
|
}
|
|
@@ -136,9 +105,6 @@ export const callPhoneTool = {
|
|
|
136
105
|
slotId: slotId,
|
|
137
106
|
message: "电话拨打成功",
|
|
138
107
|
};
|
|
139
|
-
logger.log(`[CALL_PHONE_TOOL] 🎉 Call initiated successfully`);
|
|
140
|
-
logger.log(`[CALL_PHONE_TOOL] - phoneNumber: ${params.phoneNumber}`);
|
|
141
|
-
logger.log(`[CALL_PHONE_TOOL] - slotId: ${slotId}`);
|
|
142
108
|
resolve({
|
|
143
109
|
content: [
|
|
144
110
|
{
|
|
@@ -149,19 +115,14 @@ export const callPhoneTool = {
|
|
|
149
115
|
});
|
|
150
116
|
}
|
|
151
117
|
else {
|
|
152
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Call failed`);
|
|
153
|
-
logger.error(`[CALL_PHONE_TOOL] - status: ${event.status}`);
|
|
154
|
-
logger.error(`[CALL_PHONE_TOOL] - outputs:`, JSON.stringify(event.outputs || {}));
|
|
155
118
|
const errorDetail = event.outputs ? JSON.stringify(event.outputs) : event.status;
|
|
156
119
|
reject(new Error(`拨打电话失败: ${errorDetail}`));
|
|
157
120
|
}
|
|
158
121
|
}
|
|
159
122
|
};
|
|
160
123
|
// Register event handler
|
|
161
|
-
logger.log(`[CALL_PHONE_TOOL] 📡 Registering data-event handler on WebSocket manager`);
|
|
162
124
|
wsManager.on("data-event", handler);
|
|
163
125
|
// Send the command
|
|
164
|
-
logger.log(`[CALL_PHONE_TOOL] 📤 Sending StartCall command...`);
|
|
165
126
|
sendCommand({
|
|
166
127
|
config,
|
|
167
128
|
sessionId,
|
|
@@ -170,10 +131,8 @@ export const callPhoneTool = {
|
|
|
170
131
|
command,
|
|
171
132
|
})
|
|
172
133
|
.then(() => {
|
|
173
|
-
logger.log(`[CALL_PHONE_TOOL] ✅ Command sent successfully, waiting for response...`);
|
|
174
134
|
})
|
|
175
135
|
.catch((error) => {
|
|
176
|
-
logger.error(`[CALL_PHONE_TOOL] ❌ Failed to send command:`, error);
|
|
177
136
|
clearTimeout(timeout);
|
|
178
137
|
wsManager.off("data-event", handler);
|
|
179
138
|
reject(error);
|