@ynhcj/xiaoyi-channel 0.0.202-beta → 0.0.204-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.
Files changed (119) hide show
  1. package/dist/index.js +3 -3
  2. package/dist/src/bot.js +52 -34
  3. package/dist/src/channel.js +68 -64
  4. package/dist/src/client.d.ts +5 -0
  5. package/dist/src/client.js +10 -0
  6. package/dist/src/cspl/call_api.js +2 -0
  7. package/dist/src/cspl/sentinel_hook.js +9 -8
  8. package/dist/src/formatter.js +21 -31
  9. package/dist/src/monitor.js +20 -9
  10. package/dist/src/outbound.js +5 -0
  11. package/dist/src/provider.js +42 -13
  12. package/dist/src/reply-dispatcher.d.ts +3 -0
  13. package/dist/src/reply-dispatcher.js +146 -159
  14. package/dist/src/self-evolution-handler.js +2 -1
  15. package/dist/src/task-manager.d.ts +5 -6
  16. package/dist/src/task-manager.js +5 -9
  17. package/dist/src/tools/agent-as-skill-tool.d.ts +41 -2
  18. package/dist/src/tools/agent-as-skill-tool.js +144 -146
  19. package/dist/src/tools/calendar-tool.d.ts +24 -2
  20. package/dist/src/tools/calendar-tool.js +115 -117
  21. package/dist/src/tools/call-device-tool.d.ts +20 -6
  22. package/dist/src/tools/call-device-tool.js +116 -138
  23. package/dist/src/tools/call-phone-tool.d.ts +21 -2
  24. package/dist/src/tools/call-phone-tool.js +112 -114
  25. package/dist/src/tools/check-plugin-privilege-tool.d.ts +16 -2
  26. package/dist/src/tools/check-plugin-privilege-tool.js +141 -143
  27. package/dist/src/tools/create-alarm-tool.d.ts +39 -2
  28. package/dist/src/tools/create-alarm-tool.js +229 -231
  29. package/dist/src/tools/create-all-tools.js +0 -2
  30. package/dist/src/tools/delete-alarm-tool.d.ts +15 -2
  31. package/dist/src/tools/delete-alarm-tool.js +134 -136
  32. package/dist/src/tools/device-tool-map.js +3 -2
  33. package/dist/src/tools/discover-cross-devices-tool.d.ts +16 -2
  34. package/dist/src/tools/discover-cross-devices-tool.js +121 -124
  35. package/dist/src/tools/display-a2ui-card-bypath-tool.d.ts +21 -2
  36. package/dist/src/tools/display-a2ui-card-bypath-tool.js +53 -56
  37. package/dist/src/tools/get-alarm-tool-schema.d.ts +1 -2
  38. package/dist/src/tools/get-alarm-tool-schema.js +10 -16
  39. package/dist/src/tools/get-calendar-tool-schema.d.ts +1 -2
  40. package/dist/src/tools/get-calendar-tool-schema.js +8 -12
  41. package/dist/src/tools/get-collection-tool-schema.d.ts +1 -2
  42. package/dist/src/tools/get-collection-tool-schema.js +9 -11
  43. package/dist/src/tools/get-contact-tool-schema.d.ts +1 -2
  44. package/dist/src/tools/get-contact-tool-schema.js +10 -16
  45. package/dist/src/tools/get-device-file-tool-schema.d.ts +1 -2
  46. package/dist/src/tools/get-device-file-tool-schema.js +9 -13
  47. package/dist/src/tools/get-email-tool-schema.d.ts +1 -2
  48. package/dist/src/tools/get-email-tool-schema.js +8 -11
  49. package/dist/src/tools/get-note-tool-schema.d.ts +1 -2
  50. package/dist/src/tools/get-note-tool-schema.js +9 -14
  51. package/dist/src/tools/get-photo-tool-schema.d.ts +1 -2
  52. package/dist/src/tools/get-photo-tool-schema.js +9 -12
  53. package/dist/src/tools/image-reading-tool.d.ts +28 -2
  54. package/dist/src/tools/image-reading-tool.js +76 -76
  55. package/dist/src/tools/location-tool.d.ts +11 -2
  56. package/dist/src/tools/location-tool.js +93 -92
  57. package/dist/src/tools/login-token-tool.d.ts +20 -2
  58. package/dist/src/tools/login-token-tool.js +123 -125
  59. package/dist/src/tools/modify-alarm-tool.d.ts +47 -2
  60. package/dist/src/tools/modify-alarm-tool.js +250 -252
  61. package/dist/src/tools/modify-note-tool.d.ts +20 -2
  62. package/dist/src/tools/modify-note-tool.js +107 -109
  63. package/dist/src/tools/note-tool.d.ts +20 -2
  64. package/dist/src/tools/note-tool.js +106 -108
  65. package/dist/src/tools/query-app-message-tool.d.ts +28 -2
  66. package/dist/src/tools/query-app-message-tool.js +111 -113
  67. package/dist/src/tools/query-memory-data-tool.d.ts +28 -2
  68. package/dist/src/tools/query-memory-data-tool.js +112 -114
  69. package/dist/src/tools/query-todo-task-tool.d.ts +24 -2
  70. package/dist/src/tools/query-todo-task-tool.js +106 -108
  71. package/dist/src/tools/save-file-to-phone-tool.d.ts +24 -2
  72. package/dist/src/tools/save-file-to-phone-tool.js +130 -132
  73. package/dist/src/tools/save-media-to-gallery-tool.d.ts +24 -2
  74. package/dist/src/tools/save-media-to-gallery-tool.js +137 -139
  75. package/dist/src/tools/save-self-evolution-skill-tool.d.ts +54 -2
  76. package/dist/src/tools/save-self-evolution-skill-tool.js +194 -194
  77. package/dist/src/tools/search-alarm-tool.d.ts +34 -2
  78. package/dist/src/tools/search-alarm-tool.js +174 -176
  79. package/dist/src/tools/search-calendar-tool.d.ts +24 -2
  80. package/dist/src/tools/search-calendar-tool.js +148 -150
  81. package/dist/src/tools/search-contact-tool.d.ts +16 -2
  82. package/dist/src/tools/search-contact-tool.js +101 -103
  83. package/dist/src/tools/search-email-tool.d.ts +21 -2
  84. package/dist/src/tools/search-email-tool.js +110 -112
  85. package/dist/src/tools/search-file-tool.d.ts +16 -2
  86. package/dist/src/tools/search-file-tool.js +104 -106
  87. package/dist/src/tools/search-message-tool.d.ts +16 -2
  88. package/dist/src/tools/search-message-tool.js +103 -105
  89. package/dist/src/tools/search-note-tool.d.ts +16 -2
  90. package/dist/src/tools/search-note-tool.js +98 -100
  91. package/dist/src/tools/search-photo-gallery-tool.d.ts +21 -2
  92. package/dist/src/tools/search-photo-gallery-tool.js +35 -37
  93. package/dist/src/tools/send-cross-device-task-tool.d.ts +35 -2
  94. package/dist/src/tools/send-cross-device-task-tool.js +140 -143
  95. package/dist/src/tools/send-email-tool.d.ts +24 -2
  96. package/dist/src/tools/send-email-tool.js +108 -110
  97. package/dist/src/tools/send-file-to-user-tool.d.ts +20 -2
  98. package/dist/src/tools/send-file-to-user-tool.js +174 -176
  99. package/dist/src/tools/send-html-card-tool.d.ts +20 -2
  100. package/dist/src/tools/send-html-card-tool.js +85 -87
  101. package/dist/src/tools/send-message-tool.d.ts +20 -2
  102. package/dist/src/tools/send-message-tool.js +122 -124
  103. package/dist/src/tools/session-manager.d.ts +7 -50
  104. package/dist/src/tools/session-manager.js +40 -231
  105. package/dist/src/tools/upload-file-tool.d.ts +20 -2
  106. package/dist/src/tools/upload-file-tool.js +80 -82
  107. package/dist/src/tools/upload-photo-tool.d.ts +20 -2
  108. package/dist/src/tools/upload-photo-tool.js +68 -70
  109. package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +32 -2
  110. package/dist/src/tools/xiaoyi-add-collection-tool.js +146 -148
  111. package/dist/src/tools/xiaoyi-collection-tool.d.ts +20 -2
  112. package/dist/src/tools/xiaoyi-collection-tool.js +114 -116
  113. package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +15 -2
  114. package/dist/src/tools/xiaoyi-delete-collection-tool.js +127 -129
  115. package/dist/src/tools/xiaoyi-gui-tool.d.ts +16 -2
  116. package/dist/src/tools/xiaoyi-gui-tool.js +92 -95
  117. package/dist/src/utils/logger.js +3 -14
  118. package/dist/src/websocket.d.ts +1 -1
  119. package/package.json +1 -1
@@ -10,8 +10,9 @@ import { handleLoginTokenEvent } from "./login-token-handler.js";
10
10
  import { handleCronQueryEvent } from "./cron-query-handler.js";
11
11
  import { handleMemoryQueryEvent } from "./memory-query-handler.js";
12
12
  import { cleanupStaleTempFiles } from "./reply-dispatcher.js";
13
- import { cleanupStaleSessions, getActiveSessionCount, cleanupAllSessions } from "./tools/session-manager.js";
14
13
  import { logger } from "./utils/logger.js";
14
+ import { XYFileUploadService } from "./file-upload.js";
15
+ import { startLogReporter } from "./log-reporter/index.js";
15
16
  /**
16
17
  * Per-session serial queue that ensures messages from the same session are processed
17
18
  * in arrival order while allowing different sessions to run concurrently.
@@ -75,6 +76,8 @@ export async function monitorXYProvider(opts = {}) {
75
76
  let globalDispatchInitGate = Promise.resolve();
76
77
  // Health check interval
77
78
  let healthCheckInterval = null;
79
+ // Log reporter stop handle
80
+ let stopLogReporter = null;
78
81
  return new Promise((resolve, reject) => {
79
82
  // Event handlers (defined early so they can be referenced in cleanup)
80
83
  const messageHandler = (message, sessionId, serverId) => {
@@ -214,6 +217,11 @@ export async function monitorXYProvider(opts = {}) {
214
217
  };
215
218
  const cleanup = () => {
216
219
  logger.log("XY gateway: cleaning up...");
220
+ // Stop log reporter
221
+ if (stopLogReporter) {
222
+ stopLogReporter();
223
+ stopLogReporter = null;
224
+ }
217
225
  // 🔍 Diagnose before cleanup
218
226
  logger.log("[DIAGNOSTICS] Checking WebSocket managers before cleanup...");
219
227
  diagnoseAllManagers();
@@ -239,8 +247,7 @@ export async function monitorXYProvider(opts = {}) {
239
247
  wsManager.disconnect();
240
248
  // ✅ Remove manager from cache to prevent reusing dirty state
241
249
  removeXYWebSocketManager(account);
242
- // Clean up all active sessions
243
- cleanupAllSessions();
250
+ // Session context is ALS-scoped now — nothing global to clean up.
244
251
  loggedServers.clear();
245
252
  activeMessages.clear();
246
253
  logger.log(`[MONITOR-HANDLER] Cleanup complete, cleared active messages and sessions`);
@@ -309,12 +316,7 @@ export async function monitorXYProvider(opts = {}) {
309
316
  if (cleaned > 0) {
310
317
  logger.log(`[HEALTH CHECK] Auto-cleaned ${cleaned} manager(s) with orphan connections`);
311
318
  }
312
- // Cleanup stale sessions (older than 10min TTL)
313
- const cleanedSessions = cleanupStaleSessions();
314
- const remainingSessions = getActiveSessionCount();
315
- if (cleanedSessions > 0 || remainingSessions > 0) {
316
- logger.log(`[HEALTH CHECK] Sessions: cleaned=${cleanedSessions}, active=${remainingSessions}`);
317
- }
319
+ // Session context is ALS-scoped no global session cleanup needed.
318
320
  // Cleanup stale temp files (older than 24 hours)
319
321
  void cleanupStaleTempFiles();
320
322
  }, 6 * 60 * 60 * 1000); // 6 hours
@@ -322,6 +324,15 @@ export async function monitorXYProvider(opts = {}) {
322
324
  wsManager.connect()
323
325
  .then(() => {
324
326
  logger.log("XY gateway: started successfully");
327
+ // Start log reporter (independent periodic scanner + uploader)
328
+ startLogReporter({
329
+ configPath: "/home/ynhcj/.openclaw/log-reporter-config.json",
330
+ uploadService: new XYFileUploadService(account.fileUploadUrl, account.apiKey, account.uid),
331
+ }).then((stop) => {
332
+ stopLogReporter = stop;
333
+ }).catch((err) => {
334
+ logger.warn(`Log reporter not started: ${String(err)}`);
335
+ });
325
336
  })
326
337
  .catch((err) => {
327
338
  // Connection failed but don't reject - continue monitoring for reconnection
@@ -1,3 +1,7 @@
1
+ // Outbound adapter for XY channel
2
+ // Following feishu/outbound.ts pattern
3
+ // NOTE: Using any for compatibility with SDK 2026.3.24
4
+ import os from "os";
1
5
  import { resolveXYConfig } from "./config.js";
2
6
  import { XYFileUploadService } from "./file-upload.js";
3
7
  import { XYPushService } from "./push.js";
@@ -219,6 +223,7 @@ export const xyOutbound = {
219
223
  },
220
224
  },
221
225
  error: { code: 0 },
226
+ hostname: os.hostname(),
222
227
  }),
223
228
  };
224
229
  // Get WebSocket manager and send message
@@ -398,6 +398,10 @@ function trimUserMetadata(text) {
398
398
  * bot.ts stores them as MessageSid = "xiaoyi_taskId_deviceType".
399
399
  * The "xiaoyi_" prefix ensures extraction only happens for messages
400
400
  * routed through xiaoyi-channel, not other channels sharing the provider.
401
+ *
402
+ * This is the most reliable source during steer scenarios: ALS still holds
403
+ * the first message's taskId, but the text extraction sees the latest
404
+ * injected user message which carries the updated taskId.
401
405
  */
402
406
  function extractA2AFromConversationInfo(text) {
403
407
  const match = text.match(/Conversation info \(untrusted metadata\):\n```json\n([\s\S]*?)\n```/);
@@ -424,7 +428,12 @@ export const xiaoyiProvider = {
424
428
  * xiaoyiprovider as long as the provider has a configured baseUrl.
425
429
  */
426
430
  resolveDynamicModel: (ctx) => {
427
- const baseUrl = ctx.providerConfig?.baseUrl;
431
+ // providerConfig from models.providers.xiaoyiprovider is preferred;
432
+ // fall back to zai baseUrl when config-driven provider setup is unavailable.
433
+ let baseUrl = ctx.providerConfig?.baseUrl;
434
+ if (!baseUrl || typeof baseUrl !== "string") {
435
+ baseUrl = ctx.config?.models?.providers?.zai?.baseUrl;
436
+ }
428
437
  if (!baseUrl || typeof baseUrl !== "string")
429
438
  return null;
430
439
  return {
@@ -433,7 +442,7 @@ export const xiaoyiProvider = {
433
442
  api: ctx.providerConfig?.api ?? "openai-completions",
434
443
  provider: "xiaoyiprovider",
435
444
  baseUrl,
436
- reasoning: false,
445
+ reasoning: true,
437
446
  input: ["text"],
438
447
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
439
448
  contextWindow: 256_000,
@@ -477,6 +486,8 @@ export const xiaoyiProvider = {
477
486
  // ── Extract A2A taskId/deviceType from Conversation info ──
478
487
  // bot.ts stores taskId_deviceType as MessageSid, which the framework
479
488
  // renders as message_id in the Conversation info JSON block.
489
+ // This is the priority source: it reflects the latest user message
490
+ // even during steer when ALS still holds the first message's taskId.
480
491
  let extractedTaskId = null;
481
492
  let extractedDeviceType = null;
482
493
  if (context.messages) {
@@ -502,8 +513,9 @@ export const xiaoyiProvider = {
502
513
  // ── Build dynamic headers ────────────────────────────
503
514
  // Priority:
504
515
  // 1. Cron-triggered: uid → cronUuid, with cron-specific headers
505
- // 2. Xiaoyi A2A: taskId extracted from Conversation info (xiaoyi_ prefix)
506
- // 3. UID-based fallback: sha256(uid).hex[:32]_timestamp
516
+ // 2. Xiaoyi A2A: taskId from Conversation info text (latest msg, steer-safe)
517
+ // 3. ALS fallback: rawTaskId from AsyncLocalStorage
518
+ // 4. UID-based fallback: sha256(uid).hex[:32]_timestamp
507
519
  const isCron = isCronTriggered(context.messages);
508
520
  if (isCron) {
509
521
  // fire 期 jobId 桥:把首条消息 `[cron:<jobId> ...]` 解析出的真实 jobId
@@ -533,6 +545,7 @@ export const xiaoyiProvider = {
533
545
  dynamicHeaders["x-cron-title"] = encodeURIComponent(cronTitle);
534
546
  if (context.messages?.length === 1)
535
547
  dynamicHeaders["x-cron-flag"] = "begin";
548
+ logger.log(`[ALS-PROOF] provider headers source=cron`);
536
549
  }
537
550
  else if (extractedTaskId) {
538
551
  const sessionId = extractedTaskId.split("&")[0];
@@ -540,14 +553,31 @@ export const xiaoyiProvider = {
540
553
  dynamicHeaders[HEADER_TRACE_ID] = extractedTaskId;
541
554
  dynamicHeaders[HEADER_SESSION_ID] = sessionId;
542
555
  dynamicHeaders[HEADER_INTERACTION_ID] = interactionId;
556
+ logger.log(`[ALS-PROOF] provider headers source=text-extract traceId=${extractedTaskId} sessionId=${sessionId} interactionId=${interactionId}`);
543
557
  }
544
558
  else {
545
- const fallbackPrefix = ctx.extraParams?.[FALLBACK_PREFIX_KEY];
546
- if (typeof fallbackPrefix === "string") {
547
- const fallbackValue = `${fallbackPrefix}_${Date.now()}`;
548
- dynamicHeaders[HEADER_TRACE_ID] = fallbackValue;
549
- dynamicHeaders[HEADER_SESSION_ID] = fallbackValue;
550
- dynamicHeaders[HEADER_INTERACTION_ID] = fallbackValue;
559
+ // ALS fallback: rawTaskId from the per-turn AsyncLocalStorage scope.
560
+ // Text extraction (above) is preferred because during steer the ALS
561
+ // scope may still hold the first message's taskId.
562
+ const als = getCurrentSessionContext();
563
+ const rawTaskId = als?.taskId;
564
+ if (rawTaskId) {
565
+ const sessionId = rawTaskId.split("&")[0];
566
+ const interactionId = rawTaskId.split("&")[1] ?? "";
567
+ dynamicHeaders[HEADER_TRACE_ID] = rawTaskId;
568
+ dynamicHeaders[HEADER_SESSION_ID] = sessionId;
569
+ dynamicHeaders[HEADER_INTERACTION_ID] = interactionId;
570
+ logger.log(`[ALS-PROOF] provider headers source=ALS traceId=${rawTaskId} sessionId=${sessionId} interactionId=${interactionId}`);
571
+ }
572
+ else {
573
+ const fallbackPrefix = ctx.extraParams?.[FALLBACK_PREFIX_KEY];
574
+ if (typeof fallbackPrefix === "string") {
575
+ const fallbackValue = `${fallbackPrefix}_${Date.now()}`;
576
+ dynamicHeaders[HEADER_TRACE_ID] = fallbackValue;
577
+ dynamicHeaders[HEADER_SESSION_ID] = fallbackValue;
578
+ dynamicHeaders[HEADER_INTERACTION_ID] = fallbackValue;
579
+ }
580
+ logger.log(`[ALS-PROOF] provider headers source=uid-fallback (ALS miss)`);
551
581
  }
552
582
  }
553
583
  // 记录输入
@@ -560,8 +590,7 @@ export const xiaoyiProvider = {
560
590
  if (context.systemPrompt) {
561
591
  logger.log(`[xiaoyiprovider] system prompt length: ${context.systemPrompt.length}`);
562
592
  }
563
- // deviceType: prefer value extracted from Conversation info,
564
- // then ALS fallback.
593
+ // deviceType: prefer text-extracted value, ALS as fallback.
565
594
  const deviceType = extractedDeviceType
566
595
  ?? getCurrentSessionContext()?.deviceType;
567
596
  // app_ver and sdk_api_version from session context (ALS)
@@ -618,7 +647,7 @@ export const xiaoyiProvider = {
618
647
  deviceSection += `当前用户小艺APP版本是${appVer}\n`;
619
648
  }
620
649
  if (sdkApiVersion) {
621
- deviceSection += `当前用户系统软件API版本是${sdkApiVersion}\n`;
650
+ deviceSection += `当前用户系统Rom版本是${sdkApiVersion}\n`;
622
651
  }
623
652
  deviceSection += `You need to be aware of the user's current device and provide guidance accordingly. If the response involves device-related tools or actions, you must tailor the reply based on the user's current device, using device-specific references such as "saved to the Notes/Calendar on your {deviceType}.\n"`;
624
653
  context.systemPrompt = (context.systemPrompt ?? "") + deviceSection;
@@ -9,6 +9,9 @@ export interface CreateXYReplyDispatcherParams {
9
9
  steerState: {
10
10
  steered: boolean;
11
11
  };
12
+ /** Called at end of onIdle, after final frame is sent. openclaw's waitForIdle() does
13
+ * not await the async onIdle, so cleanup must happen inside onIdle itself. */
14
+ onIdleComplete?: () => void | Promise<void>;
12
15
  }
13
16
  /**
14
17
  * 清理 /tmp/xy_channel 目录中超过 24 小时的旧文件