@ynhcj/xiaoyi-channel 0.0.144-beta → 0.0.146-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 +2 -2
- package/dist/src/provider.js +52 -23
- package/package.json +1 -1
package/dist/src/bot.js
CHANGED
|
@@ -270,7 +270,7 @@ export async function handleXYMessage(params) {
|
|
|
270
270
|
SenderId: parsed.sessionId,
|
|
271
271
|
Provider: "xiaoyi-channel",
|
|
272
272
|
Surface: "xiaoyi-channel",
|
|
273
|
-
MessageSid:
|
|
273
|
+
MessageSid: `xiaoyi_${parsed.taskId}_${deviceType}`,
|
|
274
274
|
Timestamp: Date.now(),
|
|
275
275
|
WasMentioned: false,
|
|
276
276
|
CommandAuthorized: true,
|
|
@@ -532,7 +532,7 @@ async function dispatchSteerWhenReady(params) {
|
|
|
532
532
|
SenderId: sessionId,
|
|
533
533
|
Provider: "xiaoyi-channel",
|
|
534
534
|
Surface: "xiaoyi-channel",
|
|
535
|
-
MessageSid:
|
|
535
|
+
MessageSid: `xiaoyi_${params.parsed.taskId}_${params.deviceType}`,
|
|
536
536
|
Timestamp: Date.now(),
|
|
537
537
|
WasMentioned: false,
|
|
538
538
|
CommandAuthorized: true,
|
package/dist/src/provider.js
CHANGED
|
@@ -46,6 +46,11 @@ function getFirstUserText(messages) {
|
|
|
46
46
|
}
|
|
47
47
|
/** Regex to match `[cron:<uuid> <title>]` anywhere in text. */
|
|
48
48
|
const CRON_TAG_RE = /\[cron:[^\s\]]+\s+([^\]]+)\]/;
|
|
49
|
+
/** Extract the cron job UUID from the first user message, e.g. `[cron:abc123 ...]` → `abc123`. */
|
|
50
|
+
function extractCronUuid(messages) {
|
|
51
|
+
const match = getFirstUserText(messages).match(/\[cron:([^\s\]]+)/i);
|
|
52
|
+
return match ? match[1] : undefined;
|
|
53
|
+
}
|
|
49
54
|
/** Check if the request is triggered by a cron job by inspecting the first user message. */
|
|
50
55
|
function isCronTriggered(messages) {
|
|
51
56
|
return /\[cron:/i.test(getFirstUserText(messages));
|
|
@@ -392,7 +397,9 @@ function trimUserMetadata(text) {
|
|
|
392
397
|
}
|
|
393
398
|
/**
|
|
394
399
|
* Extract A2A taskId and deviceType from Conversation info JSON.
|
|
395
|
-
* bot.ts stores them as MessageSid = "
|
|
400
|
+
* bot.ts stores them as MessageSid = "xiaoyi_taskId_deviceType".
|
|
401
|
+
* The "xiaoyi_" prefix ensures extraction only happens for messages
|
|
402
|
+
* routed through xiaoyi-channel, not other channels sharing the provider.
|
|
396
403
|
*/
|
|
397
404
|
function extractA2AFromConversationInfo(text) {
|
|
398
405
|
const match = text.match(/Conversation info \(untrusted metadata\):\n```json\n([\s\S]*?)\n```/);
|
|
@@ -402,9 +409,9 @@ function extractA2AFromConversationInfo(text) {
|
|
|
402
409
|
if (!msgIdMatch)
|
|
403
410
|
return null;
|
|
404
411
|
const parts = msgIdMatch[1].split("_");
|
|
405
|
-
if (parts.length <
|
|
412
|
+
if (parts.length < 3 || parts[0] !== "xiaoyi")
|
|
406
413
|
return null;
|
|
407
|
-
return { taskId: parts[
|
|
414
|
+
return { taskId: parts[1], deviceType: parts[2] };
|
|
408
415
|
}
|
|
409
416
|
export const xiaoyiProvider = {
|
|
410
417
|
id: "xiaoyiprovider",
|
|
@@ -488,15 +495,20 @@ export const xiaoyiProvider = {
|
|
|
488
495
|
}
|
|
489
496
|
}
|
|
490
497
|
// ── Build dynamic headers ────────────────────────────
|
|
498
|
+
// Priority:
|
|
499
|
+
// 1. TaskId extracted from Conversation info in user messages (most reliable
|
|
500
|
+
// — based on message content, not mutable global state or cached values)
|
|
501
|
+
// 2. UID-based fallback: sha256(uid).hex[:32]_timestamp
|
|
502
|
+
// 3. Cached extraParams from prepareExtraParams (session keys)
|
|
491
503
|
if (ctx.extraParams) {
|
|
492
504
|
const fallbackPrefix = ctx.extraParams[FALLBACK_PREFIX_KEY];
|
|
493
|
-
if (
|
|
494
|
-
//
|
|
505
|
+
if (extractedTaskId) {
|
|
506
|
+
// Session mode: taskId extracted from Conversation info
|
|
507
|
+
const traceId = extractedTaskId;
|
|
508
|
+
const sessionId = traceId.split("&")[0];
|
|
509
|
+
const interactionId = traceId.split("&")[1] ?? "";
|
|
495
510
|
const isCron = isCronTriggered(context.messages);
|
|
496
|
-
|
|
497
|
-
dynamicHeaders[HEADER_TRACE_ID] = isCron ? `cron_${fallbackValue}` : fallbackValue;
|
|
498
|
-
dynamicHeaders[HEADER_SESSION_ID] = fallbackValue;
|
|
499
|
-
dynamicHeaders[HEADER_INTERACTION_ID] = fallbackValue;
|
|
511
|
+
dynamicHeaders[HEADER_TRACE_ID] = isCron ? `cron_${traceId}_${Date.now()}` : traceId;
|
|
500
512
|
if (isCron) {
|
|
501
513
|
const cronTitle = extractCronTitle(context.messages);
|
|
502
514
|
if (cronTitle)
|
|
@@ -504,14 +516,16 @@ export const xiaoyiProvider = {
|
|
|
504
516
|
if (context.messages?.length === 1)
|
|
505
517
|
dynamicHeaders["x-cron-flag"] = "begin";
|
|
506
518
|
}
|
|
519
|
+
dynamicHeaders[HEADER_SESSION_ID] = sessionId;
|
|
520
|
+
dynamicHeaders[HEADER_INTERACTION_ID] = interactionId;
|
|
507
521
|
}
|
|
508
|
-
else if (
|
|
509
|
-
//
|
|
510
|
-
const traceId = extractedTaskId;
|
|
511
|
-
const sessionId = traceId.split("&")[0];
|
|
512
|
-
const interactionId = traceId.split("&")[1] ?? "";
|
|
522
|
+
else if (typeof fallbackPrefix === "string") {
|
|
523
|
+
// Fallback mode: generate fresh timestamp per request
|
|
513
524
|
const isCron = isCronTriggered(context.messages);
|
|
514
|
-
|
|
525
|
+
const fallbackValue = `${fallbackPrefix}_${Date.now()}`;
|
|
526
|
+
dynamicHeaders[HEADER_TRACE_ID] = isCron ? `cron_${fallbackValue}` : fallbackValue;
|
|
527
|
+
dynamicHeaders[HEADER_SESSION_ID] = fallbackValue;
|
|
528
|
+
dynamicHeaders[HEADER_INTERACTION_ID] = fallbackValue;
|
|
515
529
|
if (isCron) {
|
|
516
530
|
const cronTitle = extractCronTitle(context.messages);
|
|
517
531
|
if (cronTitle)
|
|
@@ -519,20 +533,35 @@ export const xiaoyiProvider = {
|
|
|
519
533
|
if (context.messages?.length === 1)
|
|
520
534
|
dynamicHeaders["x-cron-flag"] = "begin";
|
|
521
535
|
}
|
|
522
|
-
dynamicHeaders[HEADER_SESSION_ID] = sessionId;
|
|
523
|
-
dynamicHeaders[HEADER_INTERACTION_ID] = interactionId;
|
|
524
536
|
}
|
|
525
537
|
else {
|
|
526
538
|
// Fallback: use extraParams cached values
|
|
527
539
|
const traceId = ctx.extraParams[HEADER_TRACE_ID];
|
|
528
540
|
const sessionId = ctx.extraParams[HEADER_SESSION_ID];
|
|
529
541
|
const interactionId = ctx.extraParams[HEADER_INTERACTION_ID];
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
542
|
+
const isCronCached = isCronTriggered(context.messages);
|
|
543
|
+
if (isCronCached) {
|
|
544
|
+
// Cron: generate fresh sessionId from cron UUID so each invocation
|
|
545
|
+
// is independently tracked, regardless of stale activeSessions state.
|
|
546
|
+
const cronUuid = extractCronUuid(context.messages) ?? "cron";
|
|
547
|
+
const cronSessionId = `cron_${cronUuid}_${Date.now()}`;
|
|
548
|
+
dynamicHeaders[HEADER_TRACE_ID] = cronSessionId;
|
|
549
|
+
dynamicHeaders[HEADER_SESSION_ID] = cronUuid;
|
|
550
|
+
dynamicHeaders[HEADER_INTERACTION_ID] = cronSessionId;
|
|
551
|
+
const cronTitle = extractCronTitle(context.messages);
|
|
552
|
+
if (cronTitle)
|
|
553
|
+
dynamicHeaders["x-cron-title"] = encodeURIComponent(cronTitle);
|
|
554
|
+
if (context.messages?.length === 1)
|
|
555
|
+
dynamicHeaders["x-cron-flag"] = "begin";
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
if (typeof traceId === "string")
|
|
559
|
+
dynamicHeaders[HEADER_TRACE_ID] = traceId;
|
|
560
|
+
if (typeof sessionId === "string")
|
|
561
|
+
dynamicHeaders[HEADER_SESSION_ID] = sessionId;
|
|
562
|
+
if (typeof interactionId === "string")
|
|
563
|
+
dynamicHeaders[HEADER_INTERACTION_ID] = interactionId;
|
|
564
|
+
}
|
|
536
565
|
}
|
|
537
566
|
}
|
|
538
567
|
// 记录输入
|