@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.
- package/dist/index.js +3 -3
- package/dist/src/bot.js +52 -34
- package/dist/src/channel.js +68 -64
- package/dist/src/client.d.ts +5 -0
- package/dist/src/client.js +10 -0
- package/dist/src/cspl/call_api.js +2 -0
- package/dist/src/cspl/sentinel_hook.js +9 -8
- package/dist/src/formatter.js +21 -31
- package/dist/src/monitor.js +20 -9
- package/dist/src/outbound.js +5 -0
- package/dist/src/provider.js +42 -13
- package/dist/src/reply-dispatcher.d.ts +3 -0
- package/dist/src/reply-dispatcher.js +146 -159
- package/dist/src/self-evolution-handler.js +2 -1
- package/dist/src/task-manager.d.ts +5 -6
- package/dist/src/task-manager.js +5 -9
- package/dist/src/tools/agent-as-skill-tool.d.ts +41 -2
- package/dist/src/tools/agent-as-skill-tool.js +144 -146
- package/dist/src/tools/calendar-tool.d.ts +24 -2
- package/dist/src/tools/calendar-tool.js +115 -117
- package/dist/src/tools/call-device-tool.d.ts +20 -6
- package/dist/src/tools/call-device-tool.js +116 -138
- package/dist/src/tools/call-phone-tool.d.ts +21 -2
- package/dist/src/tools/call-phone-tool.js +112 -114
- package/dist/src/tools/check-plugin-privilege-tool.d.ts +16 -2
- package/dist/src/tools/check-plugin-privilege-tool.js +141 -143
- package/dist/src/tools/create-alarm-tool.d.ts +39 -2
- package/dist/src/tools/create-alarm-tool.js +229 -231
- package/dist/src/tools/create-all-tools.js +0 -2
- package/dist/src/tools/delete-alarm-tool.d.ts +15 -2
- package/dist/src/tools/delete-alarm-tool.js +134 -136
- package/dist/src/tools/device-tool-map.js +3 -2
- package/dist/src/tools/discover-cross-devices-tool.d.ts +16 -2
- package/dist/src/tools/discover-cross-devices-tool.js +121 -124
- package/dist/src/tools/display-a2ui-card-bypath-tool.d.ts +21 -2
- package/dist/src/tools/display-a2ui-card-bypath-tool.js +53 -56
- package/dist/src/tools/get-alarm-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-alarm-tool-schema.js +10 -16
- package/dist/src/tools/get-calendar-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-calendar-tool-schema.js +8 -12
- package/dist/src/tools/get-collection-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-collection-tool-schema.js +9 -11
- package/dist/src/tools/get-contact-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-contact-tool-schema.js +10 -16
- package/dist/src/tools/get-device-file-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-device-file-tool-schema.js +9 -13
- package/dist/src/tools/get-email-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-email-tool-schema.js +8 -11
- package/dist/src/tools/get-note-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-note-tool-schema.js +9 -14
- package/dist/src/tools/get-photo-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-photo-tool-schema.js +9 -12
- package/dist/src/tools/image-reading-tool.d.ts +28 -2
- package/dist/src/tools/image-reading-tool.js +76 -76
- package/dist/src/tools/location-tool.d.ts +11 -2
- package/dist/src/tools/location-tool.js +93 -92
- package/dist/src/tools/login-token-tool.d.ts +20 -2
- package/dist/src/tools/login-token-tool.js +123 -125
- package/dist/src/tools/modify-alarm-tool.d.ts +47 -2
- package/dist/src/tools/modify-alarm-tool.js +250 -252
- package/dist/src/tools/modify-note-tool.d.ts +20 -2
- package/dist/src/tools/modify-note-tool.js +107 -109
- package/dist/src/tools/note-tool.d.ts +20 -2
- package/dist/src/tools/note-tool.js +106 -108
- package/dist/src/tools/query-app-message-tool.d.ts +28 -2
- package/dist/src/tools/query-app-message-tool.js +111 -113
- package/dist/src/tools/query-memory-data-tool.d.ts +28 -2
- package/dist/src/tools/query-memory-data-tool.js +112 -114
- package/dist/src/tools/query-todo-task-tool.d.ts +24 -2
- package/dist/src/tools/query-todo-task-tool.js +106 -108
- package/dist/src/tools/save-file-to-phone-tool.d.ts +24 -2
- package/dist/src/tools/save-file-to-phone-tool.js +130 -132
- package/dist/src/tools/save-media-to-gallery-tool.d.ts +24 -2
- package/dist/src/tools/save-media-to-gallery-tool.js +137 -139
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +54 -2
- package/dist/src/tools/save-self-evolution-skill-tool.js +194 -194
- package/dist/src/tools/search-alarm-tool.d.ts +34 -2
- package/dist/src/tools/search-alarm-tool.js +174 -176
- package/dist/src/tools/search-calendar-tool.d.ts +24 -2
- package/dist/src/tools/search-calendar-tool.js +148 -150
- package/dist/src/tools/search-contact-tool.d.ts +16 -2
- package/dist/src/tools/search-contact-tool.js +101 -103
- package/dist/src/tools/search-email-tool.d.ts +21 -2
- package/dist/src/tools/search-email-tool.js +110 -112
- package/dist/src/tools/search-file-tool.d.ts +16 -2
- package/dist/src/tools/search-file-tool.js +104 -106
- package/dist/src/tools/search-message-tool.d.ts +16 -2
- package/dist/src/tools/search-message-tool.js +103 -105
- package/dist/src/tools/search-note-tool.d.ts +16 -2
- package/dist/src/tools/search-note-tool.js +98 -100
- package/dist/src/tools/search-photo-gallery-tool.d.ts +21 -2
- package/dist/src/tools/search-photo-gallery-tool.js +35 -37
- package/dist/src/tools/send-cross-device-task-tool.d.ts +35 -2
- package/dist/src/tools/send-cross-device-task-tool.js +140 -143
- package/dist/src/tools/send-email-tool.d.ts +24 -2
- package/dist/src/tools/send-email-tool.js +108 -110
- package/dist/src/tools/send-file-to-user-tool.d.ts +20 -2
- package/dist/src/tools/send-file-to-user-tool.js +174 -176
- package/dist/src/tools/send-html-card-tool.d.ts +20 -2
- package/dist/src/tools/send-html-card-tool.js +85 -87
- package/dist/src/tools/send-message-tool.d.ts +20 -2
- package/dist/src/tools/send-message-tool.js +122 -124
- package/dist/src/tools/session-manager.d.ts +7 -50
- package/dist/src/tools/session-manager.js +40 -231
- package/dist/src/tools/upload-file-tool.d.ts +20 -2
- package/dist/src/tools/upload-file-tool.js +80 -82
- package/dist/src/tools/upload-photo-tool.d.ts +20 -2
- package/dist/src/tools/upload-photo-tool.js +68 -70
- package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +32 -2
- package/dist/src/tools/xiaoyi-add-collection-tool.js +146 -148
- package/dist/src/tools/xiaoyi-collection-tool.d.ts +20 -2
- package/dist/src/tools/xiaoyi-collection-tool.js +114 -116
- package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +15 -2
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +127 -129
- package/dist/src/tools/xiaoyi-gui-tool.d.ts +16 -2
- package/dist/src/tools/xiaoyi-gui-tool.js +92 -95
- package/dist/src/utils/logger.js +3 -14
- package/dist/src/websocket.d.ts +1 -1
- package/package.json +1 -1
package/dist/src/monitor.js
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
//
|
|
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
|
package/dist/src/outbound.js
CHANGED
|
@@ -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
|
package/dist/src/provider.js
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
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
|
|
506
|
-
// 3.
|
|
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
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
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
|
|
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 +=
|
|
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 小时的旧文件
|