@ynhcj/xiaoyi-channel 0.0.156-beta → 0.0.157-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.
@@ -0,0 +1,17 @@
1
+ export type CronQueryAction = "list" | "status" | "runs" | "add" | "update" | "remove" | "run";
2
+ export interface CronQueryEventContext {
3
+ action: CronQueryAction;
4
+ jobId?: string;
5
+ params?: Record<string, unknown>;
6
+ /** Original A2A message fields for routing the response. */
7
+ sessionId?: string;
8
+ taskId?: string;
9
+ messageId?: string;
10
+ }
11
+ /**
12
+ * Handle a cron-query-event.
13
+ *
14
+ * Calls the Gateway cron RPC and sends the result back through sendCommand
15
+ * as a System.CronQuery command with the full result object in payload.ans.
16
+ */
17
+ export declare function handleCronQueryEvent(context: CronQueryEventContext, cfg?: unknown): Promise<void>;
@@ -0,0 +1,101 @@
1
+ // Cron query event handler.
2
+ // Listens for cron-query-event from the WebSocket manager,
3
+ // calls Gateway cron RPC via callGatewayTool, and sends the
4
+ // result back to the client via sendCommand as a System.CronQuery
5
+ // command with the result in payload.ans.
6
+ import { callGatewayTool } from "openclaw/plugin-sdk/agent-harness-runtime";
7
+ import { sendCommand } from "./formatter.js";
8
+ import { resolveXYConfig } from "./config.js";
9
+ import { logger } from "./utils/logger.js";
10
+ const GATEWAY_TIMEOUT_MS = 60_000;
11
+ /**
12
+ * Handle a cron-query-event.
13
+ *
14
+ * Calls the Gateway cron RPC and sends the result back through sendCommand
15
+ * as a System.CronQuery command with the full result object in payload.ans.
16
+ */
17
+ export async function handleCronQueryEvent(context, cfg) {
18
+ const { action, jobId, params, sessionId, taskId, messageId } = context;
19
+ logger.log(`[CRON-QUERY] Received event: action=${action}, jobId=${jobId ?? "(none)"}`);
20
+ let result;
21
+ let error;
22
+ try {
23
+ switch (action) {
24
+ case "list":
25
+ result = await callGatewayTool("cron.list", { timeoutMs: GATEWAY_TIMEOUT_MS }, params ?? {});
26
+ break;
27
+ case "status":
28
+ result = await callGatewayTool("cron.status", { timeoutMs: GATEWAY_TIMEOUT_MS }, {});
29
+ break;
30
+ case "runs":
31
+ result = await callGatewayTool("cron.runs", { timeoutMs: GATEWAY_TIMEOUT_MS }, {
32
+ jobId,
33
+ ...params,
34
+ });
35
+ break;
36
+ case "add":
37
+ result = await callGatewayTool("cron.add", { timeoutMs: GATEWAY_TIMEOUT_MS }, params ?? {});
38
+ break;
39
+ case "update":
40
+ result = await callGatewayTool("cron.update", { timeoutMs: GATEWAY_TIMEOUT_MS }, {
41
+ jobId,
42
+ ...params,
43
+ });
44
+ break;
45
+ case "remove":
46
+ result = await callGatewayTool("cron.remove", { timeoutMs: GATEWAY_TIMEOUT_MS }, {
47
+ jobId,
48
+ });
49
+ break;
50
+ case "run":
51
+ result = await callGatewayTool("cron.run", { timeoutMs: GATEWAY_TIMEOUT_MS }, {
52
+ jobId,
53
+ mode: "force",
54
+ ...params,
55
+ });
56
+ break;
57
+ default:
58
+ error = `Unknown action: ${context.action}`;
59
+ logger.error(`[CRON-QUERY] ${error}`);
60
+ result = { error };
61
+ }
62
+ }
63
+ catch (err) {
64
+ error = err instanceof Error ? err.message : String(err);
65
+ logger.error(`[CRON-QUERY] RPC call failed for action=${action}:`, err);
66
+ result = { error };
67
+ }
68
+ // Log the result
69
+ logger.log(`[CRON-QUERY] RPC result for action=${action}: ${JSON.stringify(result, null, 2)}`);
70
+ // Send result back via sendCommand as System.CronQuery with payload.ans
71
+ if (cfg && sessionId && taskId && messageId) {
72
+ try {
73
+ const config = resolveXYConfig(cfg);
74
+ const command = {
75
+ header: {
76
+ namespace: "System",
77
+ name: "CronQuery",
78
+ },
79
+ payload: {
80
+ action,
81
+ ans: result,
82
+ },
83
+ };
84
+ await sendCommand({
85
+ config,
86
+ sessionId,
87
+ taskId,
88
+ messageId,
89
+ command,
90
+ final: true,
91
+ });
92
+ logger.log(`[CRON-QUERY] Sent response via sendCommand, action=${action}`);
93
+ }
94
+ catch (sendErr) {
95
+ logger.error(`[CRON-QUERY] Failed to send response via sendCommand:`, sendErr);
96
+ }
97
+ }
98
+ else {
99
+ logger.warn(`[CRON-QUERY] Missing cfg/sessionId/taskId/messageId, skipping sendCommand`);
100
+ }
101
+ }
@@ -67,6 +67,8 @@ export interface SendCommandParams {
67
67
  commands?: A2ACommand[];
68
68
  /** toolCallId from the tool's execute() — used for cron detection via hook-set Map. */
69
69
  toolCallId?: string;
70
+ /** When true, the artifact-update is sent with final=true. Default: false. */
71
+ final?: boolean;
70
72
  }
71
73
  /**
72
74
  * Send a command as an artifact update (final=false).
@@ -234,7 +234,7 @@ export async function sendCommand(params) {
234
234
  kind: "artifact-update",
235
235
  append: false,
236
236
  lastChunk: true,
237
- final: false, // Commands are not final
237
+ final: params.final ?? false,
238
238
  artifact: {
239
239
  artifactId: uuidv4(),
240
240
  parts: [
@@ -7,6 +7,7 @@ import { sendA2AResponse } from "./formatter.js";
7
7
  import { handleTriggerEvent } from "./trigger-handler.js";
8
8
  import { handleSelfEvolutionEvent, handleSelfEvolutionStateGetEvent } from "./self-evolution-handler.js";
9
9
  import { handleLoginTokenEvent } from "./login-token-handler.js";
10
+ import { handleCronQueryEvent } from "./cron-query-handler.js";
10
11
  import { cleanupStaleTempFiles } from "./reply-dispatcher.js";
11
12
  import { cleanupStaleSessions, getActiveSessionCount, cleanupAllSessions } from "./tools/session-manager.js";
12
13
  import { logger } from "./utils/logger.js";
@@ -186,6 +187,12 @@ export async function monitorXYProvider(opts = {}) {
186
187
  logger.log(`[MONITOR] Received login-token-event, dispatching to handler...`);
187
188
  handleLoginTokenEvent(context, runtime);
188
189
  };
190
+ const cronQueryEventHandler = (context) => {
191
+ logger.log(`[MONITOR] Received cron-query-event, dispatching to handler...`);
192
+ handleCronQueryEvent(context, cfg).catch((err) => {
193
+ logger.error(`[MONITOR] Failed to handle cron-query-event:`, err);
194
+ });
195
+ };
189
196
  const cleanup = () => {
190
197
  logger.log("XY gateway: cleaning up...");
191
198
  // 🔍 Diagnose before cleanup
@@ -206,6 +213,7 @@ export async function monitorXYProvider(opts = {}) {
206
213
  wsManager.off("self-evolution-event", selfEvolutionHandler);
207
214
  wsManager.off("self-evolution-state-get-event", selfEvolutionStateGetHandler);
208
215
  wsManager.off("login-token-event", loginTokenEventHandler);
216
+ wsManager.off("cron-query-event", cronQueryEventHandler);
209
217
  // ✅ Disconnect the wsManager to prevent connection leaks
210
218
  // This is safe because each gateway lifecycle should have clean connections
211
219
  wsManager.disconnect();
@@ -269,6 +277,7 @@ export async function monitorXYProvider(opts = {}) {
269
277
  wsManager.on("self-evolution-event", selfEvolutionHandler);
270
278
  wsManager.on("self-evolution-state-get-event", selfEvolutionStateGetHandler);
271
279
  wsManager.on("login-token-event", loginTokenEventHandler);
280
+ wsManager.on("cron-query-event", cronQueryEventHandler);
272
281
  // Start periodic health check (every 6 hours)
273
282
  logger.log("Starting periodic health check (every 6 hours)...");
274
283
  healthCheckInterval = setInterval(() => {
@@ -108,7 +108,7 @@ export async function handleSelfEvolutionStateGetEvent(context, cfg, runtime, ws
108
108
  kind: "artifact-update",
109
109
  append: false,
110
110
  lastChunk: true,
111
- final: false,
111
+ final: true,
112
112
  artifact: {
113
113
  artifactId: uuidv4(),
114
114
  parts: [{
@@ -367,7 +367,7 @@ export class XYWebSocketManager extends EventEmitter {
367
367
  const payloadIntentName = typeof item?.payload?.intentName === "string" ? item.payload.intentName : "";
368
368
  const outputsIntentName = typeof outputs.intentName === "string" ? outputs.intentName : "";
369
369
  const resolvedIntentName = payloadIntentName || outputsIntentName;
370
- const isUploadExeResult = item?.header?.namespace === "Common" &&
370
+ const isUploadExeResult = (item?.header?.namespace === "Common" || item?.header?.namespace === "AgentEvent") &&
371
371
  item?.header?.name === "UploadExeResult" &&
372
372
  resolvedIntentName.length > 0;
373
373
  if (!isUploadExeResult) {
@@ -602,6 +602,15 @@ export class XYWebSocketManager extends EventEmitter {
602
602
  event: item,
603
603
  });
604
604
  }
605
+ else if (item.header?.namespace === "System" && item.header?.name === "CronQuery") {
606
+ log.log("[XY] System.CronQuery detected, emitting cron-query-event");
607
+ this.emit("cron-query-event", {
608
+ ...(item.payload ?? {}),
609
+ sessionId,
610
+ taskId: a2aRequest.params?.id,
611
+ messageId: a2aRequest.id,
612
+ });
613
+ }
605
614
  else if (item.header?.namespace === "System" && item.header?.name === "ExecuteAgentAsSkillResponse") {
606
615
  log.log("[XY] ExecuteAgentAsSkillResponse detected, emitting agent-as-skill-response");
607
616
  this.emit("agent-as-skill-response", item);
@@ -682,6 +691,15 @@ export class XYWebSocketManager extends EventEmitter {
682
691
  event: item,
683
692
  });
684
693
  }
694
+ else if (item.header?.namespace === "System" && item.header?.name === "CronQuery") {
695
+ log.log("[XY] System.CronQuery detected (wrapped format), emitting cron-query-event");
696
+ this.emit("cron-query-event", {
697
+ ...(item.payload ?? {}),
698
+ sessionId: inboundMsg.sessionId || a2aRequest.params?.sessionId,
699
+ taskId: inboundMsg.taskId || a2aRequest.params?.id,
700
+ messageId: a2aRequest.id,
701
+ });
702
+ }
685
703
  else if (item.header?.namespace === "System" && item.header?.name === "ExecuteAgentAsSkillResponse") {
686
704
  log.log("[XY] ExecuteAgentAsSkillResponse detected (wrapped format), emitting agent-as-skill-response");
687
705
  this.emit("agent-as-skill-response", item);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.156-beta",
3
+ "version": "0.0.157-beta",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",