@ynhcj/xiaoyi 2.1.7 → 2.1.8

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/channel.js CHANGED
@@ -365,19 +365,95 @@ exports.xiaoyiPlugin = {
365
365
  });
366
366
  // Setup cancel handler
367
367
  connection.on("cancel", async (data) => {
368
- console.log(`Handling cancel request for task: ${data.taskId}`);
368
+ console.log("\n" + "=".repeat(60));
369
+ console.log(`XiaoYi: [CANCEL] Received cancel request`);
370
+ console.log(` Session: ${data.sessionId}`);
371
+ console.log(` Task ID: ${data.taskId || "N/A"}`);
372
+ console.log("=".repeat(60) + "\n");
369
373
  // CRITICAL: Use dynamic require to get the latest runtime module after hot-reload
370
374
  const { getXiaoYiRuntime } = require("./runtime");
371
375
  const runtime = getXiaoYiRuntime();
372
- // Get PluginRuntime and emit cancel event
373
- const pluginRuntime = runtime.getPluginRuntime();
374
- if (pluginRuntime) {
375
- pluginRuntime.emit("task:cancel", {
376
- channel: "xiaoyi",
377
- accountId: resolvedAccount.accountId,
378
- taskId: data.taskId,
379
- sessionId: data.sessionId,
380
- });
376
+ // Build SessionKey to match the format used in message handler
377
+ const sessionKey = `xiaoyi:${resolvedAccount.accountId}:${data.sessionId}`;
378
+ // Try to abort the running agent using OpenClaw's internal API
379
+ try {
380
+ // Try to load OpenClaw's internal abort function
381
+ // Note: This requires the plugin to be run within OpenClaw's environment
382
+ const abortEmbeddedPiRun = globalThis["__openclaw_abortEmbeddedPiRun"] ||
383
+ (() => {
384
+ try {
385
+ const openclawPath = require.resolve("openclaw");
386
+ const runsModule = require(`${openclawPath}/dist/agents/pi-embedded-runner/runs.js`);
387
+ return runsModule.abortEmbeddedPiRun;
388
+ }
389
+ catch {
390
+ return null;
391
+ }
392
+ })();
393
+ if (!abortEmbeddedPiRun) {
394
+ console.warn(`XiaoYi: [CANCEL] abortEmbeddedPiRun not available, falling back to event emission`);
395
+ throw new Error("abortEmbeddedPiRun not available");
396
+ }
397
+ // Try to load session store functions
398
+ const loadSessionStore = globalThis["__openclaw_loadSessionStore"] ||
399
+ (() => {
400
+ try {
401
+ const openclawPath = require.resolve("openclaw");
402
+ const sessionModule = require(`${openclawPath}/dist/config/sessions.js`);
403
+ return sessionModule.loadSessionStore;
404
+ }
405
+ catch {
406
+ return null;
407
+ }
408
+ })();
409
+ const resolveStorePath = globalThis["__openclaw_resolveStorePath"] ||
410
+ (() => {
411
+ try {
412
+ const openclawPath = require.resolve("openclaw");
413
+ const sessionModule = require(`${openclawPath}/dist/config/sessions.js`);
414
+ return sessionModule.resolveStorePath;
415
+ }
416
+ catch {
417
+ return null;
418
+ }
419
+ })();
420
+ if (!loadSessionStore || !resolveStorePath) {
421
+ console.warn(`XiaoYi: [CANCEL] Session store functions not available`);
422
+ throw new Error("Session store functions not available");
423
+ }
424
+ // Load session store and find the internal sessionId
425
+ const agentId = resolvedAccount.config.agentId || "default";
426
+ const storePath = resolveStorePath(config.session?.store, { agentId });
427
+ const store = loadSessionStore(storePath);
428
+ const sessionEntry = store[sessionKey];
429
+ if (sessionEntry && sessionEntry.sessionId) {
430
+ console.log(`XiaoYi: [CANCEL] Found session entry with internal sessionId: ${sessionEntry.sessionId}`);
431
+ // Abort the running agent
432
+ const aborted = abortEmbeddedPiRun(sessionEntry.sessionId);
433
+ if (aborted) {
434
+ console.log(`XiaoYi: [CANCEL] ✓ Successfully aborted agent run for session: ${data.sessionId}\n`);
435
+ }
436
+ else {
437
+ console.warn(`XiaoYi: [CANCEL] ⚠ No active run found for session: ${data.sessionId}\n`);
438
+ }
439
+ }
440
+ else {
441
+ console.warn(`XiaoYi: [CANCEL] ⚠ No session entry found for key: ${sessionKey}\n`);
442
+ }
443
+ }
444
+ catch (error) {
445
+ console.error(`XiaoYi: [CANCEL] Error aborting agent:`, error);
446
+ // Fallback: emit cancel event for any listeners
447
+ const pluginRuntime = runtime.getPluginRuntime();
448
+ if (pluginRuntime) {
449
+ pluginRuntime.emit("task:cancel", {
450
+ channel: "xiaoyi",
451
+ accountId: resolvedAccount.accountId,
452
+ taskId: data.taskId,
453
+ sessionId: data.sessionId,
454
+ });
455
+ console.log(`XiaoYi: [CANCEL] Emitted task:cancel event as fallback\n`);
456
+ }
381
457
  }
382
458
  // Send success response
383
459
  const connection = runtime.getConnection();
package/dist/types.d.ts CHANGED
@@ -104,6 +104,7 @@ export interface A2AClearContextResult {
104
104
  };
105
105
  }
106
106
  export interface A2ATasksCancelResult {
107
+ id: string;
107
108
  status: {
108
109
  state: "canceled" | "failed" | "unknown";
109
110
  };
@@ -131,9 +132,12 @@ export interface A2ATasksCancelMessage {
131
132
  agentId: string;
132
133
  sessionId: string;
133
134
  id: string;
134
- action: "tasks/cancel";
135
- taskId: string;
136
- timestamp: number;
135
+ action?: "tasks/cancel";
136
+ method?: "tasks/cancel";
137
+ taskId?: string;
138
+ jsonrpc?: "2.0";
139
+ conversationId?: string;
140
+ timestamp?: number;
137
141
  }
138
142
  export interface XiaoYiChannelConfig {
139
143
  enabled: boolean;
package/dist/websocket.js CHANGED
@@ -165,10 +165,18 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
165
165
  jsonrpc: "2.0",
166
166
  id: requestId,
167
167
  result: {
168
+ id: requestId, // 使用请求中的该字段返回
168
169
  status: {
169
170
  state: success ? "canceled" : "failed"
170
171
  }
171
172
  },
173
+ error: success ? {
174
+ code: 0,
175
+ message: ""
176
+ } : {
177
+ code: -1,
178
+ message: "Failed to cancel task"
179
+ },
172
180
  };
173
181
  const message = {
174
182
  msgType: "agent_response",
@@ -334,8 +342,8 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
334
342
  this.handleClearMessage(message);
335
343
  return;
336
344
  }
337
- // Check if it's a tasks/cancel message
338
- if (message.action === "tasks/cancel") {
345
+ // Check if it's a tasks/cancel message (支持 method 和 action 两种格式)
346
+ if (message.method === "tasks/cancel" || message.action === "tasks/cancel") {
339
347
  this.handleTasksCancelMessage(message);
340
348
  return;
341
349
  }
@@ -373,11 +381,15 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
373
381
  * Reference: https://developer.huawei.com/consumer/cn/doc/service/tasks-cancel-0000002537561193
374
382
  */
375
383
  handleTasksCancelMessage(message) {
376
- console.log(`Received tasks/cancel message for task: ${message.taskId}`);
384
+ // Use taskId if available, otherwise use id as the task identifier
385
+ const effectiveTaskId = message.taskId || message.id;
386
+ console.log(`Received tasks/cancel message for task: ${effectiveTaskId}`);
387
+ console.log(` Session: ${message.sessionId}`);
388
+ console.log(` Message ID: ${message.id}`);
377
389
  // Emit cancel event for application to handle
378
390
  this.emit("cancel", {
379
391
  sessionId: message.sessionId,
380
- taskId: message.taskId,
392
+ taskId: effectiveTaskId,
381
393
  id: message.id,
382
394
  });
383
395
  // Note: We'll send the success response after OpenClaw confirms cancellation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi",
3
- "version": "2.1.7",
3
+ "version": "2.1.8",
4
4
  "description": "XiaoYi channel plugin for OpenClaw",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",