@ynhcj/xiaoyi-channel 0.0.41-beta → 0.0.43-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 +41 -2
- package/dist/src/formatter.d.ts +14 -0
- package/dist/src/formatter.js +46 -0
- package/dist/src/parser.d.ts +7 -0
- package/dist/src/parser.js +22 -0
- package/dist/src/trigger-handler.d.ts +3 -0
- package/dist/src/trigger-handler.js +18 -50
- package/package.json +1 -1
package/dist/src/bot.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { getXYRuntime } from "./runtime.js";
|
|
2
2
|
import { createXYReplyDispatcher } from "./reply-dispatcher.js";
|
|
3
|
-
import { parseA2AMessage, extractTextFromParts, extractFileParts, extractPushId } from "./parser.js";
|
|
3
|
+
import { parseA2AMessage, extractTextFromParts, extractFileParts, extractPushId, extractTriggerData } from "./parser.js";
|
|
4
4
|
import { resolveXYConfig } from "./config.js";
|
|
5
|
-
import { sendStatusUpdate, sendClearContextResponse, sendTasksCancelResponse } from "./formatter.js";
|
|
5
|
+
import { sendStatusUpdate, sendClearContextResponse, sendTasksCancelResponse, sendA2AResponse } from "./formatter.js";
|
|
6
6
|
import { registerSession, unregisterSession, runWithSessionContext } from "./tools/session-manager.js";
|
|
7
7
|
import { configManager } from "./utils/config-manager.js";
|
|
8
8
|
import { addPushId } from "./utils/pushid-manager.js";
|
|
9
|
+
import { getPushDataById } from "./utils/pushdata-manager.js";
|
|
9
10
|
import { registerTaskId, decrementTaskIdRef, lockTaskId, unlockTaskId, hasActiveTask, } from "./task-manager.js";
|
|
10
11
|
/**
|
|
11
12
|
* Handle an incoming A2A message.
|
|
@@ -57,6 +58,44 @@ export async function handleXYMessage(params) {
|
|
|
57
58
|
}
|
|
58
59
|
// Parse the A2A message (for regular messages)
|
|
59
60
|
const parsed = parseA2AMessage(message);
|
|
61
|
+
// ========== 检测 Trigger 消息 ==========
|
|
62
|
+
// 如果消息中包含 Trigger 事件数据,直接返回 pushData 内容,不走正常流程
|
|
63
|
+
const triggerData = extractTriggerData(parsed.parts);
|
|
64
|
+
if (triggerData) {
|
|
65
|
+
log(`[BOT] 📌 Detected Trigger message with pushDataId: ${triggerData.pushDataId}`);
|
|
66
|
+
log(`[BOT] - Session ID: ${parsed.sessionId}`);
|
|
67
|
+
log(`[BOT] - Task ID: ${parsed.taskId}`);
|
|
68
|
+
try {
|
|
69
|
+
// 读取 pushData
|
|
70
|
+
const pushDataItem = await getPushDataById(triggerData.pushDataId);
|
|
71
|
+
if (!pushDataItem) {
|
|
72
|
+
error(`[BOT] ❌ pushData not found for ID: ${triggerData.pushDataId}`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
log(`[BOT] ✅ Found pushData, sending direct response`);
|
|
76
|
+
log(`[BOT] - pushDataId: ${pushDataItem.pushDataId}`);
|
|
77
|
+
log(`[BOT] - time: ${pushDataItem.time}`);
|
|
78
|
+
log(`[BOT] - content length: ${pushDataItem.dataDetail.length} chars`);
|
|
79
|
+
const config = resolveXYConfig(cfg);
|
|
80
|
+
// 直接发送响应(final=true,不走 openclaw 流程)
|
|
81
|
+
await sendA2AResponse({
|
|
82
|
+
config,
|
|
83
|
+
sessionId: parsed.sessionId,
|
|
84
|
+
taskId: parsed.taskId,
|
|
85
|
+
messageId: parsed.messageId,
|
|
86
|
+
text: pushDataItem.dataDetail,
|
|
87
|
+
append: false,
|
|
88
|
+
final: true,
|
|
89
|
+
});
|
|
90
|
+
log(`[BOT] ✅ Trigger response sent successfully, exiting early`);
|
|
91
|
+
return; // 提前返回,不继续处理
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
error(`[BOT] ❌ Failed to handle Trigger message:`, err);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ========================================
|
|
60
99
|
// 🔑 检测steer模式和是否是第二条消息
|
|
61
100
|
const isSteerMode = cfg.messages?.queue?.mode === "steer";
|
|
62
101
|
const isSecondMessage = isSteerMode && hasActiveTask(parsed.sessionId);
|
package/dist/src/formatter.d.ts
CHANGED
|
@@ -92,3 +92,17 @@ export interface SendTasksCancelResponseParams {
|
|
|
92
92
|
* Send a tasks/cancel response.
|
|
93
93
|
*/
|
|
94
94
|
export declare function sendTasksCancelResponse(params: SendTasksCancelResponseParams): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Parameters for sending a Trigger response.
|
|
97
|
+
*/
|
|
98
|
+
export interface SendTriggerResponseParams {
|
|
99
|
+
config: XYChannelConfig;
|
|
100
|
+
sessionId: string;
|
|
101
|
+
taskId: string;
|
|
102
|
+
messageId: string;
|
|
103
|
+
content: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Send a Trigger response with pushData content.
|
|
107
|
+
*/
|
|
108
|
+
export declare function sendTriggerResponse(params: SendTriggerResponseParams): Promise<void>;
|
package/dist/src/formatter.js
CHANGED
|
@@ -293,3 +293,49 @@ export async function sendTasksCancelResponse(params) {
|
|
|
293
293
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
294
294
|
log(`Sent tasks/cancel response: sessionId=${sessionId}, taskId=${taskId}`);
|
|
295
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Send a Trigger response with pushData content.
|
|
298
|
+
*/
|
|
299
|
+
export async function sendTriggerResponse(params) {
|
|
300
|
+
const { config, sessionId, taskId, messageId, content } = params;
|
|
301
|
+
const runtime = getXYRuntime();
|
|
302
|
+
const log = runtime?.log ?? console.log;
|
|
303
|
+
const error = runtime?.error ?? console.error;
|
|
304
|
+
// Build JSON-RPC response for Trigger
|
|
305
|
+
const jsonRpcResponse = {
|
|
306
|
+
jsonrpc: "2.0",
|
|
307
|
+
id: messageId,
|
|
308
|
+
result: {
|
|
309
|
+
taskId: taskId,
|
|
310
|
+
kind: "artifact-update",
|
|
311
|
+
append: false,
|
|
312
|
+
lastChunk: true,
|
|
313
|
+
final: true,
|
|
314
|
+
artifact: {
|
|
315
|
+
artifactId: uuidv4(),
|
|
316
|
+
parts: [
|
|
317
|
+
{
|
|
318
|
+
kind: "text",
|
|
319
|
+
text: content,
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
error: {
|
|
325
|
+
code: 0,
|
|
326
|
+
message: "",
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
// Send via WebSocket
|
|
330
|
+
const wsManager = getXYWebSocketManager(config);
|
|
331
|
+
const outboundMessage = {
|
|
332
|
+
msgType: "agent_response",
|
|
333
|
+
agentId: config.agentId,
|
|
334
|
+
sessionId,
|
|
335
|
+
taskId,
|
|
336
|
+
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
337
|
+
};
|
|
338
|
+
log(`[TRIGGER_RESPONSE] Sending Trigger response: sessionId=${sessionId}, taskId=${taskId}`);
|
|
339
|
+
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
340
|
+
log(`[TRIGGER_RESPONSE] Trigger response sent successfully`);
|
|
341
|
+
}
|
package/dist/src/parser.d.ts
CHANGED
|
@@ -43,6 +43,13 @@ export declare function isTasksCancelMessage(method: string): boolean;
|
|
|
43
43
|
* Looks for push_id in data parts under variables.systemVariables.push_id
|
|
44
44
|
*/
|
|
45
45
|
export declare function extractPushId(parts: A2AMessagePart[]): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Extract Trigger event data from message parts.
|
|
48
|
+
* Looks for Trigger events with pushDataId in data parts.
|
|
49
|
+
*/
|
|
50
|
+
export declare function extractTriggerData(parts: A2AMessagePart[]): {
|
|
51
|
+
pushDataId: string;
|
|
52
|
+
} | null;
|
|
46
53
|
/**
|
|
47
54
|
* Validate A2A request structure.
|
|
48
55
|
*/
|
package/dist/src/parser.js
CHANGED
|
@@ -72,6 +72,28 @@ export function extractPushId(parts) {
|
|
|
72
72
|
}
|
|
73
73
|
return null;
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Extract Trigger event data from message parts.
|
|
77
|
+
* Looks for Trigger events with pushDataId in data parts.
|
|
78
|
+
*/
|
|
79
|
+
export function extractTriggerData(parts) {
|
|
80
|
+
for (const part of parts) {
|
|
81
|
+
if (part.kind === "data" && part.data) {
|
|
82
|
+
const events = part.data.events;
|
|
83
|
+
if (Array.isArray(events)) {
|
|
84
|
+
for (const event of events) {
|
|
85
|
+
if (event.header?.namespace === "Common" && event.header?.name === "Trigger") {
|
|
86
|
+
const pushDataId = event.payload?.dataMap?.pushDataId;
|
|
87
|
+
if (pushDataId && typeof pushDataId === "string") {
|
|
88
|
+
return { pushDataId };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
75
97
|
/**
|
|
76
98
|
* Validate A2A request structure.
|
|
77
99
|
*/
|
|
@@ -11,6 +11,9 @@ export interface TriggerEventContext {
|
|
|
11
11
|
* 处理 Trigger 事件
|
|
12
12
|
* 当用户在手机侧点击推送消息时触发
|
|
13
13
|
*
|
|
14
|
+
* 策略:构造一个包含 Trigger 事件的 A2A 消息,通过 handleXYMessage 处理
|
|
15
|
+
* 这样可以复用现有的消息链路和 runtime 初始化
|
|
16
|
+
*
|
|
14
17
|
* @param context - Trigger 事件上下文(包含 event, sessionId, taskId)
|
|
15
18
|
* @param cfg - OpenClaw 配置
|
|
16
19
|
* @param runtime - 运行时环境
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// Trigger 事件处理器
|
|
2
|
-
import { randomUUID } from "crypto";
|
|
3
|
-
import { getPushDataById } from "./utils/pushdata-manager.js";
|
|
4
1
|
import { handleXYMessage } from "./bot.js";
|
|
5
2
|
/**
|
|
6
3
|
* 处理 Trigger 事件
|
|
7
4
|
* 当用户在手机侧点击推送消息时触发
|
|
8
5
|
*
|
|
6
|
+
* 策略:构造一个包含 Trigger 事件的 A2A 消息,通过 handleXYMessage 处理
|
|
7
|
+
* 这样可以复用现有的消息链路和 runtime 初始化
|
|
8
|
+
*
|
|
9
9
|
* @param context - Trigger 事件上下文(包含 event, sessionId, taskId)
|
|
10
10
|
* @param cfg - OpenClaw 配置
|
|
11
11
|
* @param runtime - 运行时环境
|
|
@@ -17,73 +17,41 @@ export async function handleTriggerEvent(context, cfg, runtime, accountId) {
|
|
|
17
17
|
try {
|
|
18
18
|
const { event, sessionId, taskId } = context;
|
|
19
19
|
log(`[TRIGGER_HANDLER] 📌 Received Trigger event`);
|
|
20
|
-
log(`[TRIGGER_HANDLER]
|
|
21
|
-
log(`[TRIGGER_HANDLER]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
if (!taskId) {
|
|
27
|
-
error(`[TRIGGER_HANDLER] ❌ Missing taskId in context`);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
// 从 event.payload.dataMap 中提取 pushDataId
|
|
31
|
-
const pushDataId = event.payload?.dataMap?.pushDataId;
|
|
32
|
-
if (!pushDataId) {
|
|
33
|
-
error(`[TRIGGER_HANDLER] ❌ Missing pushDataId in Trigger event payload`);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
log(`[TRIGGER_HANDLER] 🔍 Looking up pushDataId: ${pushDataId}`);
|
|
37
|
-
// 根据 pushDataId 查询原始数据
|
|
38
|
-
const pushDataItem = await getPushDataById(pushDataId);
|
|
39
|
-
if (!pushDataItem) {
|
|
40
|
-
error(`[TRIGGER_HANDLER] ❌ pushData not found for ID: ${pushDataId}`);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
log(`[TRIGGER_HANDLER] ✅ Found pushData`);
|
|
44
|
-
log(`[TRIGGER_HANDLER] - pushDataId: ${pushDataItem.pushDataId}`);
|
|
45
|
-
log(`[TRIGGER_HANDLER] - time: ${pushDataItem.time}`);
|
|
46
|
-
log(`[TRIGGER_HANDLER] - dataDetail length: ${pushDataItem.dataDetail.length} chars`);
|
|
47
|
-
// 拼接消息
|
|
48
|
-
const prefixMessage = "这是定时任务的执行结果,你检查一下是否依赖手机侧的工具执行,如果依赖则在本轮任务中完成手机侧任务执行,如果不依赖,则直接把完整的执行结果返回给用户";
|
|
49
|
-
const fullMessage = `${prefixMessage}\n\n${pushDataItem.dataDetail}`;
|
|
50
|
-
log(`[TRIGGER_HANDLER] 📝 Constructed message (length: ${fullMessage.length} chars)`);
|
|
51
|
-
// 构造 A2A 消息
|
|
52
|
-
// 使用从 WebSocket 传递过来的 sessionId 和 taskId(新的 taskId)
|
|
53
|
-
// 这样可以触发 steer 模式,覆盖之前正在执行的任务
|
|
54
|
-
const messageId = randomUUID();
|
|
20
|
+
log(`[TRIGGER_HANDLER] - sessionId: ${sessionId}`);
|
|
21
|
+
log(`[TRIGGER_HANDLER] - taskId: ${taskId}`);
|
|
22
|
+
log(`[TRIGGER_HANDLER] - pushDataId: ${event.payload?.dataMap?.pushDataId}`);
|
|
23
|
+
// 构造包含 Trigger 事件的 A2A 消息
|
|
24
|
+
// 将原始 event 放入 message.parts 中,让 handleXYMessage 检测并处理
|
|
55
25
|
const a2aMessage = {
|
|
56
26
|
jsonrpc: "2.0",
|
|
57
27
|
method: "sendMessage",
|
|
58
|
-
id:
|
|
28
|
+
id: taskId,
|
|
59
29
|
params: {
|
|
60
|
-
id: taskId,
|
|
61
|
-
sessionId: sessionId,
|
|
30
|
+
id: taskId,
|
|
31
|
+
sessionId: sessionId,
|
|
62
32
|
agentLoginSessionId: "",
|
|
63
33
|
message: {
|
|
64
34
|
role: "user",
|
|
65
35
|
parts: [
|
|
66
36
|
{
|
|
67
|
-
kind: "
|
|
68
|
-
|
|
37
|
+
kind: "data",
|
|
38
|
+
data: {
|
|
39
|
+
events: [event], // 包含 Trigger 事件
|
|
40
|
+
},
|
|
69
41
|
},
|
|
70
42
|
],
|
|
71
43
|
},
|
|
72
44
|
},
|
|
73
45
|
};
|
|
74
|
-
log(`[TRIGGER_HANDLER] 🚀 Dispatching
|
|
75
|
-
|
|
76
|
-
log(`[TRIGGER_HANDLER] - taskId: ${taskId} (NEW - will trigger steer mode if configured)`);
|
|
77
|
-
log(`[TRIGGER_HANDLER] - messageId: ${messageId}`);
|
|
78
|
-
// 透传给 openclaw 处理
|
|
79
|
-
// 如果配置了 steer 模式,且该 sessionId 有活跃任务,这个新的 taskId 会覆盖旧的
|
|
46
|
+
log(`[TRIGGER_HANDLER] 🚀 Dispatching to handleXYMessage for processing`);
|
|
47
|
+
// 通过 handleXYMessage 处理(复用现有链路)
|
|
80
48
|
await handleXYMessage({
|
|
81
49
|
cfg,
|
|
82
50
|
runtime,
|
|
83
51
|
message: a2aMessage,
|
|
84
52
|
accountId,
|
|
85
53
|
});
|
|
86
|
-
log(`[TRIGGER_HANDLER] ✅ Trigger event
|
|
54
|
+
log(`[TRIGGER_HANDLER] ✅ Trigger event dispatched successfully`);
|
|
87
55
|
}
|
|
88
56
|
catch (err) {
|
|
89
57
|
error(`[TRIGGER_HANDLER] ❌ Failed to handle Trigger event:`, err);
|