@ynhcj/xiaoyi-channel 0.0.203-beta → 0.0.205-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 +49 -14
- package/dist/src/reply-dispatcher.d.ts +3 -0
- package/dist/src/reply-dispatcher.js +152 -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/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 -1
- 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 +2 -2
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { xiaoyiProvider } from "./src/provider.js";
|
|
|
3
3
|
import { xyPlugin } from "./src/channel.js";
|
|
4
4
|
import registerSentinelHook from "./src/cspl/sentinel_hook.js";
|
|
5
5
|
import { setXYRuntime } from "./src/runtime.js";
|
|
6
|
-
import { markCronToolCall, clearCronToolCall,
|
|
6
|
+
import { markCronToolCall, clearCronToolCall, getCurrentSessionContext } from "./src/tools/session-manager.js";
|
|
7
7
|
import { configManager } from "./src/utils/config-manager.js";
|
|
8
8
|
import { setJobPushId } from "./src/utils/cron-push-map.js";
|
|
9
9
|
import { getAllPushIds } from "./src/utils/pushid-manager.js";
|
|
@@ -54,10 +54,10 @@ async function captureCronAddMapping(event, ctx) {
|
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
console.log(`[CRONMAP] extracted jobId=${jobId}`);
|
|
57
|
-
const sessionCtx =
|
|
57
|
+
const sessionCtx = getCurrentSessionContext();
|
|
58
58
|
const sessionId = sessionCtx?.sessionId;
|
|
59
59
|
if (!sessionId) {
|
|
60
|
-
console.log(`[CRONMAP] skip: no sessionId (
|
|
60
|
+
console.log(`[CRONMAP] skip: no sessionId in ALS scope (ctxFound=${!!sessionCtx})`);
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
const pushId = await resolvePushId(sessionId);
|
package/dist/src/bot.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
|
|
1
2
|
import { updateSessionStoreEntry, updateSessionStore, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
2
3
|
import { getXYRuntime } from "./runtime.js";
|
|
3
4
|
import { createXYReplyDispatcher } from "./reply-dispatcher.js";
|
|
@@ -6,7 +7,7 @@ import { downloadFilesFromParts } from "./file-download.js";
|
|
|
6
7
|
import { resolveXYConfig } from "./config.js";
|
|
7
8
|
import { sendStatusUpdate, sendClearContextResponse, sendTasksCancelResponse, sendA2AResponse } from "./formatter.js";
|
|
8
9
|
import { appendSelfEvolutionKeywordNudge, shouldNudgeForSelfEvolutionKeyword, } from "./self-evolution-keyword.js";
|
|
9
|
-
import {
|
|
10
|
+
import { runWithSessionContext } from "./tools/session-manager.js";
|
|
10
11
|
import { configManager } from "./utils/config-manager.js";
|
|
11
12
|
import { addPushId } from "./utils/pushid-manager.js";
|
|
12
13
|
import { getPushDataById } from "./utils/pushdata-manager.js";
|
|
@@ -113,6 +114,13 @@ export async function handleXYMessage(params) {
|
|
|
113
114
|
// Steer injections skip taskId registration to avoid overwriting the active taskId
|
|
114
115
|
if (!skipReg) {
|
|
115
116
|
registerTaskId(parsed.sessionId, parsed.taskId, parsed.messageId);
|
|
117
|
+
// 🔑 steer 场景:同步更新活跃 dispatcher 的 fallback taskId/messageId
|
|
118
|
+
if (isUpdate) {
|
|
119
|
+
const updater = dispatcherUpdaters.get(parsed.sessionId);
|
|
120
|
+
if (updater) {
|
|
121
|
+
updater(parsed.taskId, parsed.messageId);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
116
124
|
// Extract and update push_id if present
|
|
117
125
|
const pushId = extractPushId(parsed.parts);
|
|
118
126
|
if (pushId) {
|
|
@@ -169,21 +177,23 @@ export async function handleXYMessage(params) {
|
|
|
169
177
|
},
|
|
170
178
|
});
|
|
171
179
|
log.log(`[BOT] Resolved route, sessionKey=${route.sessionKey}`);
|
|
172
|
-
//
|
|
180
|
+
// Check for ACP runtime binding on this A2A conversation
|
|
181
|
+
const runtimeRoute = resolveRuntimeConversationBindingRoute({
|
|
182
|
+
route,
|
|
183
|
+
channel: "xiaoyi-channel",
|
|
184
|
+
accountId,
|
|
185
|
+
conversationId: parsed.sessionId,
|
|
186
|
+
});
|
|
187
|
+
route = runtimeRoute.route;
|
|
188
|
+
if (runtimeRoute.bindingRecord) {
|
|
189
|
+
log.log(runtimeRoute.boundSessionKey
|
|
190
|
+
? `[BOT] routed via bound conversation ${parsed.sessionId} -> ${runtimeRoute.boundSessionKey}`
|
|
191
|
+
: `[BOT] plugin-bound conversation ${parsed.sessionId}`);
|
|
192
|
+
}
|
|
193
|
+
// ALS only: no registerSession. The sessionContext built below is handed
|
|
194
|
+
// to runWithSessionContext() inside withReplyDispatcher.run, which is the
|
|
195
|
+
// single wrap point for the whole agent turn.
|
|
173
196
|
if (!skipReg) {
|
|
174
|
-
registerSession(route.sessionKey, {
|
|
175
|
-
config,
|
|
176
|
-
sessionId: parsed.sessionId,
|
|
177
|
-
distributionSessionId,
|
|
178
|
-
taskId: parsed.taskId,
|
|
179
|
-
messageId: parsed.messageId,
|
|
180
|
-
agentId: route.accountId,
|
|
181
|
-
deviceType,
|
|
182
|
-
appVer: appVer ?? undefined,
|
|
183
|
-
sdkApiVersion: sdkApiVersion ?? undefined,
|
|
184
|
-
modelName,
|
|
185
|
-
runCrossTaskContext: runCrossTaskContext ?? undefined,
|
|
186
|
-
});
|
|
187
197
|
// 🔑 Sync A2A modelName to OpenClaw session store so that session_status
|
|
188
198
|
// reports the correct model. Without this, session_status returns the
|
|
189
199
|
// configured default model instead of the A2A-specified one.
|
|
@@ -354,7 +364,18 @@ export async function handleXYMessage(params) {
|
|
|
354
364
|
const steerState = { steered: false };
|
|
355
365
|
// 🔑 创建dispatcher
|
|
356
366
|
log.log(`[BOT-DISPATCHER] Creating reply dispatcher`);
|
|
357
|
-
|
|
367
|
+
// Cleanup: 必须在 onIdle 内部执行(参见 reply-dispatcher.ts 中 onIdleComplete 的注释)
|
|
368
|
+
let cleaned = false;
|
|
369
|
+
const cleanup = () => {
|
|
370
|
+
if (cleaned)
|
|
371
|
+
return;
|
|
372
|
+
cleaned = true;
|
|
373
|
+
log.log(`[BOT] Cleanup started`);
|
|
374
|
+
streamingSignals.delete(parsed.sessionId);
|
|
375
|
+
decrementTaskIdRef(parsed.sessionId);
|
|
376
|
+
log.log(`[BOT] Cleanup completed`);
|
|
377
|
+
};
|
|
378
|
+
const { dispatcher, replyOptions, markDispatchIdle, startStatusInterval, updateFallbackTaskId } = createXYReplyDispatcher({
|
|
358
379
|
cfg,
|
|
359
380
|
runtime,
|
|
360
381
|
sessionId: parsed.sessionId,
|
|
@@ -362,7 +383,10 @@ export async function handleXYMessage(params) {
|
|
|
362
383
|
messageId: parsed.messageId,
|
|
363
384
|
accountId: route.accountId,
|
|
364
385
|
steerState,
|
|
386
|
+
onIdleComplete: cleanup,
|
|
365
387
|
});
|
|
388
|
+
// 🔑 注册 dispatcher 的 fallback taskId 更新函数,供 steer 路径调用
|
|
389
|
+
dispatcherUpdaters.set(parsed.sessionId, updateFallbackTaskId);
|
|
366
390
|
// Steer injections don't need status intervals
|
|
367
391
|
if (!skipReg) {
|
|
368
392
|
startStatusInterval();
|
|
@@ -376,6 +400,8 @@ export async function handleXYMessage(params) {
|
|
|
376
400
|
messageId: parsed.messageId,
|
|
377
401
|
agentId: route.accountId,
|
|
378
402
|
deviceType,
|
|
403
|
+
appVer: appVer ?? undefined,
|
|
404
|
+
sdkApiVersion: sdkApiVersion ?? undefined,
|
|
379
405
|
modelName,
|
|
380
406
|
runCrossTaskContext: runCrossTaskContext ?? undefined,
|
|
381
407
|
};
|
|
@@ -384,15 +410,14 @@ export async function handleXYMessage(params) {
|
|
|
384
410
|
dispatcher,
|
|
385
411
|
onSettled: () => {
|
|
386
412
|
log.log(`[BOT] onSettled, steered=${steerState.steered}`);
|
|
387
|
-
// 🔑 When steered, skip
|
|
413
|
+
// 🔑 When steered, skip cleanup — the first message's dispatcher is still running
|
|
388
414
|
if (steerState.steered) {
|
|
389
415
|
log.log(`[BOT] Steered dispatch settled, skipping cleanup`);
|
|
390
416
|
return;
|
|
391
417
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
log.log(`[BOT] Cleanup completed`);
|
|
418
|
+
// cleanup 已由 onIdleComplete 在 onIdle 的 finally 中执行。
|
|
419
|
+
// onSettled 不做任何清理(直接在这里清理会发生 race condition)。
|
|
420
|
+
dispatcherUpdaters.delete(parsed.sessionId);
|
|
396
421
|
},
|
|
397
422
|
run: () => {
|
|
398
423
|
// 🔐 Use AsyncLocalStorage to provide session context to tools.
|
|
@@ -401,6 +426,7 @@ export async function handleXYMessage(params) {
|
|
|
401
426
|
// signal init complete to release the global dispatch gate
|
|
402
427
|
// for the next session.
|
|
403
428
|
const dispatchPromise = runWithSessionContext(sessionContext, async () => {
|
|
429
|
+
log.log(`[ALS-PROOF] bot entered dispatch scope sessionId=${sessionContext.sessionId} taskId=${sessionContext.taskId} isSteer=false`);
|
|
404
430
|
log.log(`[BOT-DISPATCH] dispatchReplyFromConfig starting, body.length=${ctxPayload.Body?.length ?? 0}`);
|
|
405
431
|
try {
|
|
406
432
|
const result = await core.channel.reply.dispatchReplyFromConfig({
|
|
@@ -433,7 +459,7 @@ export async function handleXYMessage(params) {
|
|
|
433
459
|
errLog.error("Failed to handle XY message:", err);
|
|
434
460
|
runtime.error?.(`xy: Failed to handle message: ${String(err)}`);
|
|
435
461
|
errLog.log(`[BOT] Error occurred, attempting cleanup`);
|
|
436
|
-
// 🔑 错误时也要清理taskId
|
|
462
|
+
// 🔑 错误时也要清理taskId(session 走 ALS,作用域退出自动清理)
|
|
437
463
|
try {
|
|
438
464
|
const params = message.params;
|
|
439
465
|
const sessionId = params?.sessionId;
|
|
@@ -441,18 +467,6 @@ export async function handleXYMessage(params) {
|
|
|
441
467
|
errLog.log(`[BOT] Cleaning up after error`);
|
|
442
468
|
// 清理 taskId
|
|
443
469
|
decrementTaskIdRef(sessionId);
|
|
444
|
-
// 清理 session
|
|
445
|
-
const core = getXYRuntime();
|
|
446
|
-
const route = core.channel.routing.resolveAgentRoute({
|
|
447
|
-
cfg,
|
|
448
|
-
channel: "xiaoyi-channel",
|
|
449
|
-
accountId,
|
|
450
|
-
peer: {
|
|
451
|
-
kind: "direct",
|
|
452
|
-
id: sessionId,
|
|
453
|
-
},
|
|
454
|
-
});
|
|
455
|
-
unregisterSession(route.sessionKey);
|
|
456
470
|
errLog.log(`[BOT] Cleanup completed after error`);
|
|
457
471
|
}
|
|
458
472
|
}
|
|
@@ -487,8 +501,11 @@ if (!_g.__xyStreamingSignals)
|
|
|
487
501
|
_g.__xyStreamingSignals = new Map();
|
|
488
502
|
if (!_g.__xySteerQueues)
|
|
489
503
|
_g.__xySteerQueues = new Map();
|
|
504
|
+
if (!_g.__xyDispatcherUpdaters)
|
|
505
|
+
_g.__xyDispatcherUpdaters = new Map();
|
|
490
506
|
const streamingSignals = _g.__xyStreamingSignals;
|
|
491
507
|
const steerQueues = _g.__xySteerQueues;
|
|
508
|
+
const dispatcherUpdaters = _g.__xyDispatcherUpdaters;
|
|
492
509
|
/**
|
|
493
510
|
* 由 provider.ts 在 wrapStreamFn 调用时触发。
|
|
494
511
|
* 这是模型 API 被调用的精确时刻,此时 isStreaming 一定为 true。
|
|
@@ -637,6 +654,7 @@ async function dispatchSteerWhenReady(params) {
|
|
|
637
654
|
},
|
|
638
655
|
run: () => {
|
|
639
656
|
return runWithSessionContext(sessionContext, async () => {
|
|
657
|
+
log.log(`[ALS-PROOF] bot entered steer dispatch scope sessionId=${sessionContext.sessionId} taskId=${sessionContext.taskId} isSteer=true`);
|
|
640
658
|
const result = await core.channel.reply.dispatchReplyFromConfig({
|
|
641
659
|
ctx: ctxPayload,
|
|
642
660
|
cfg: params.cfg,
|
package/dist/src/channel.js
CHANGED
|
@@ -2,15 +2,55 @@ import { resolveXYConfig, listXYAccountIds, getDefaultXYAccountId } from "./conf
|
|
|
2
2
|
import { xyConfigSchema } from "./config-schema.js";
|
|
3
3
|
import { xyOutbound } from "./outbound.js";
|
|
4
4
|
import { filterToolsByDevice } from "./tools/device-tool-map.js";
|
|
5
|
-
import { getCurrentSessionContext
|
|
6
|
-
import { createAllTools } from "./tools/create-all-tools.js";
|
|
5
|
+
import { getCurrentSessionContext } from "./tools/session-manager.js";
|
|
7
6
|
import { logger } from "./utils/logger.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
// Static tool imports (3.24 pattern)
|
|
8
|
+
import { locationTool } from "./tools/location-tool.js";
|
|
9
|
+
import { xiaoyiGuiTool } from "./tools/xiaoyi-gui-tool.js";
|
|
10
|
+
import { sendFileToUserTool } from "./tools/send-file-to-user-tool.js";
|
|
11
|
+
import { sendHtmlCardTool } from "./tools/send-html-card-tool.js";
|
|
12
|
+
import { viewPushResultTool } from "./tools/view-push-result-tool.js";
|
|
13
|
+
import { imageReadingTool } from "./tools/image-reading-tool.js";
|
|
14
|
+
import { timestampToUtc8Tool } from "./tools/timestamp-to-utc8-tool.js";
|
|
15
|
+
import { saveSelfEvolutionSkillTool } from "./tools/save-self-evolution-skill-tool.js";
|
|
16
|
+
import { callDeviceTool } from "./tools/call-device-tool.js";
|
|
17
|
+
import { getNoteToolSchemaTool } from "./tools/get-note-tool-schema.js";
|
|
18
|
+
import { getCalendarToolSchemaTool } from "./tools/get-calendar-tool-schema.js";
|
|
19
|
+
import { getContactToolSchemaTool } from "./tools/get-contact-tool-schema.js";
|
|
20
|
+
import { getPhotoToolSchemaTool } from "./tools/get-photo-tool-schema.js";
|
|
21
|
+
import { getDeviceFileToolSchemaTool } from "./tools/get-device-file-tool-schema.js";
|
|
22
|
+
import { getAlarmToolSchemaTool } from "./tools/get-alarm-tool-schema.js";
|
|
23
|
+
import { getCollectionToolSchemaTool } from "./tools/get-collection-tool-schema.js";
|
|
24
|
+
import { loginTokenTool } from "./tools/login-token-tool.js";
|
|
25
|
+
import { agentAsSkillTool } from "./tools/agent-as-skill-tool.js";
|
|
26
|
+
import { discoverCrossDevicesTool } from "./tools/discover-cross-devices-tool.js";
|
|
27
|
+
import { sendCrossDeviceTaskTool } from "./tools/send-cross-device-task-tool.js";
|
|
28
|
+
import { displayA2UICardByPathTool } from "./tools/display-a2ui-card-bypath-tool.js";
|
|
29
|
+
import { checkPluginPrivilegeTool } from "./tools/check-plugin-privilege-tool.js";
|
|
30
|
+
const ALL_TOOLS = [
|
|
31
|
+
locationTool,
|
|
32
|
+
discoverCrossDevicesTool,
|
|
33
|
+
sendCrossDeviceTaskTool,
|
|
34
|
+
displayA2UICardByPathTool,
|
|
35
|
+
callDeviceTool,
|
|
36
|
+
getNoteToolSchemaTool,
|
|
37
|
+
getCalendarToolSchemaTool,
|
|
38
|
+
getContactToolSchemaTool,
|
|
39
|
+
getPhotoToolSchemaTool,
|
|
40
|
+
xiaoyiGuiTool,
|
|
41
|
+
getDeviceFileToolSchemaTool,
|
|
42
|
+
getAlarmToolSchemaTool,
|
|
43
|
+
getCollectionToolSchemaTool,
|
|
44
|
+
sendFileToUserTool,
|
|
45
|
+
sendHtmlCardTool,
|
|
46
|
+
viewPushResultTool,
|
|
47
|
+
imageReadingTool,
|
|
48
|
+
timestampToUtc8Tool,
|
|
49
|
+
saveSelfEvolutionSkillTool,
|
|
50
|
+
loginTokenTool,
|
|
51
|
+
agentAsSkillTool,
|
|
52
|
+
checkPluginPrivilegeTool,
|
|
53
|
+
];
|
|
14
54
|
/**
|
|
15
55
|
* Xiaoyi Channel Plugin for OpenClaw.
|
|
16
56
|
* Implements Xiaoyi A2A protocol with dual WebSocket connections.
|
|
@@ -32,7 +72,7 @@ export const xyPlugin = {
|
|
|
32
72
|
],
|
|
33
73
|
},
|
|
34
74
|
capabilities: {
|
|
35
|
-
chatTypes: ["direct"],
|
|
75
|
+
chatTypes: ["direct"],
|
|
36
76
|
polls: false,
|
|
37
77
|
threads: false,
|
|
38
78
|
media: true,
|
|
@@ -49,59 +89,11 @@ export const xyPlugin = {
|
|
|
49
89
|
schema: xyConfigSchema,
|
|
50
90
|
},
|
|
51
91
|
outbound: xyOutbound,
|
|
52
|
-
/**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* 1. **Normal (WebSocket) session** – `getCurrentSessionContext()` returns
|
|
58
|
-
* a context that was registered by bot.ts during message processing.
|
|
59
|
-
* Tools send commands through the WebSocket and listen for responses.
|
|
60
|
-
*
|
|
61
|
-
* 2. **Cron / scheduled-task session** – openclaw's cron runner calls
|
|
62
|
-
* `agentTools({ cfg })` without an active WebSocket session. When no
|
|
63
|
-
* session context exists but `cfg` is provided, we create a synthetic
|
|
64
|
-
* "cron session" with `isCron: true` and a `cron-`-prefixed sessionId.
|
|
65
|
-
* `sendCommand()` detects this prefix and routes commands through the
|
|
66
|
-
* push channel. Response listening (WebSocket events) works unchanged
|
|
67
|
-
* because the gateway WebSocket connection is always active.
|
|
68
|
-
*/
|
|
69
|
-
agentTools: (params) => {
|
|
70
|
-
let ctx = getCurrentSessionContext();
|
|
71
|
-
// ── Cron / non-session fallback ──────────────────────────────
|
|
72
|
-
// When no active xy WebSocket session exists but the openclaw cfg
|
|
73
|
-
// is provided (framework calls agentTools({ cfg })), create a
|
|
74
|
-
// synthetic "cron session". This enables cron-triggered agent
|
|
75
|
-
// turns and cross-channel tool calls to use xiaoyi tools via the
|
|
76
|
-
// push channel. sendCommand() detects the "cron-" sessionId
|
|
77
|
-
// prefix and routes commands through push instead of WebSocket.
|
|
78
|
-
if (!ctx && params?.cfg) {
|
|
79
|
-
try {
|
|
80
|
-
const config = resolveXYConfig(params.cfg);
|
|
81
|
-
const cronId = `${CRON_SESSION_PREFIX}${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
|
|
82
|
-
ctx = {
|
|
83
|
-
config,
|
|
84
|
-
sessionId: cronId,
|
|
85
|
-
taskId: cronId,
|
|
86
|
-
messageId: cronId,
|
|
87
|
-
agentId: "default",
|
|
88
|
-
isCron: true,
|
|
89
|
-
};
|
|
90
|
-
// Register so getCurrentSessionContext() fallback can find it
|
|
91
|
-
registerSession(`__cron__${cronId}`, ctx);
|
|
92
|
-
logger.log(`[CRON-TOOLS] Created cron session context: ${cronId}`);
|
|
93
|
-
}
|
|
94
|
-
catch (err) {
|
|
95
|
-
logger.error("[CRON-TOOLS] Failed to create cron context:", err);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (!ctx) {
|
|
99
|
-
logger.log("[CREATE-ALL-TOOLS] no session context, returning empty tools list");
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
const allTools = createAllTools(ctx);
|
|
103
|
-
const filtered = filterToolsByDevice(allTools, ctx.deviceType);
|
|
104
|
-
logger.log(`[DEVICE-FILTER] deviceType=${ctx.deviceType ?? "(none)"}, tools: ${allTools.length} → ${filtered.length} (${filtered.map(t => t.name).join(", ")})`);
|
|
92
|
+
/** Static tool list (3.24 pattern). Tools read SessionContext at execute time via ALS. */
|
|
93
|
+
agentTools: () => {
|
|
94
|
+
const ctx = getCurrentSessionContext();
|
|
95
|
+
const filtered = filterToolsByDevice(ALL_TOOLS, ctx?.deviceType);
|
|
96
|
+
logger.log(`[DEVICE-FILTER] deviceType=${ctx?.deviceType ?? "(none)"}, tools: ${ALL_TOOLS.length} → ${filtered.length} (${filtered.map(t => t.name).join(", ")})`);
|
|
105
97
|
return filtered;
|
|
106
98
|
},
|
|
107
99
|
messaging: {
|
|
@@ -113,7 +105,6 @@ export const xyPlugin = {
|
|
|
113
105
|
},
|
|
114
106
|
targetResolver: {
|
|
115
107
|
looksLikeId: (raw) => {
|
|
116
|
-
// 信任所有非空字符串作为有效的 sessionId
|
|
117
108
|
const trimmed = raw.trim();
|
|
118
109
|
return trimmed.length > 0;
|
|
119
110
|
},
|
|
@@ -135,20 +126,33 @@ export const xyPlugin = {
|
|
|
135
126
|
? { conversationId, matchPriority: 2 }
|
|
136
127
|
: null;
|
|
137
128
|
},
|
|
129
|
+
resolveCommandConversation: ({ accountId }) => {
|
|
130
|
+
// xiaoyi-channel: the A2A sessionId IS the conversationId.
|
|
131
|
+
// Read from the current ALS session context.
|
|
132
|
+
const ctx = getCurrentSessionContext();
|
|
133
|
+
const sessionId = ctx?.sessionId?.trim();
|
|
134
|
+
if (!sessionId)
|
|
135
|
+
return null;
|
|
136
|
+
return { conversationId: sessionId };
|
|
137
|
+
},
|
|
138
138
|
},
|
|
139
139
|
reload: {
|
|
140
140
|
configPrefixes: ["channels.xiaoyi-channel"],
|
|
141
141
|
},
|
|
142
|
-
// Gateway adapter for receiving messages
|
|
143
142
|
gateway: {
|
|
144
143
|
async startAccount(context) {
|
|
145
144
|
const { monitorXYProvider } = await import("./monitor.js");
|
|
145
|
+
const { createXyAcpBindingManager } = await import("./acp-session-binding.js");
|
|
146
146
|
const account = resolveXYConfig(context.cfg);
|
|
147
147
|
context.setStatus?.({
|
|
148
148
|
accountId: context.accountId,
|
|
149
149
|
wsUrl: account.wsUrl,
|
|
150
150
|
});
|
|
151
151
|
context.log?.info(`[${context.accountId}] starting xiaoyi channel (wsUrl: ${account.wsUrl})`);
|
|
152
|
+
// Register ACP session binding adapter for this account.
|
|
153
|
+
// Enables sessions_spawn(runtime="acp") to bind subagent sessions
|
|
154
|
+
// to the current A2A conversation.
|
|
155
|
+
createXyAcpBindingManager({ accountId: context.accountId, cfg: context.cfg });
|
|
152
156
|
return monitorXYProvider({
|
|
153
157
|
config: context.cfg,
|
|
154
158
|
runtime: context.runtime,
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { XYWebSocketManager } from "./websocket.js";
|
|
2
2
|
import type { XYChannelConfig } from "./types.js";
|
|
3
3
|
import type { RuntimeEnv } from "openclaw/plugin-sdk";
|
|
4
|
+
/**
|
|
5
|
+
* Get a cached WebSocket manager without requiring config.
|
|
6
|
+
* Returns the first available manager. Use when ALS has no SessionContext.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCachedXYWebSocketManager(): XYWebSocketManager;
|
|
4
9
|
/**
|
|
5
10
|
* Get or create a WebSocket manager for the given configuration.
|
|
6
11
|
* Reuses existing managers if config matches.
|
package/dist/src/client.js
CHANGED
|
@@ -13,6 +13,16 @@ if (!_g.__xyWsManagerCache) {
|
|
|
13
13
|
_g.__xyWsManagerCache = new Map();
|
|
14
14
|
}
|
|
15
15
|
const wsManagerCache = _g.__xyWsManagerCache;
|
|
16
|
+
/**
|
|
17
|
+
* Get a cached WebSocket manager without requiring config.
|
|
18
|
+
* Returns the first available manager. Use when ALS has no SessionContext.
|
|
19
|
+
*/
|
|
20
|
+
export function getCachedXYWebSocketManager() {
|
|
21
|
+
if (wsManagerCache.size === 0) {
|
|
22
|
+
throw new Error("No WebSocket manager available in cache");
|
|
23
|
+
}
|
|
24
|
+
return wsManagerCache.values().next().value;
|
|
25
|
+
}
|
|
16
26
|
/**
|
|
17
27
|
* Get or create a WebSocket manager for the given configuration.
|
|
18
28
|
* Reuses existing managers if config matches.
|
|
@@ -5,6 +5,7 @@ import https from 'https';
|
|
|
5
5
|
import { URL } from 'url';
|
|
6
6
|
import { getConfig } from './config.js';
|
|
7
7
|
import { DEFAULT_HTTPS_PORT, HTTP_STATUS_BAD_REQUEST, API_URL_SUFFIX } from './constants.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
8
9
|
function buildHeadersForCelia(config, sessionId) {
|
|
9
10
|
if (!config.uid || !config.apiKey || !config.skillId || !config.requestFrom) {
|
|
10
11
|
throw new Error('[SENTINEL HOOK] Missing required configuration: uid, apiKey, skillId, or requestFrom is not defined');
|
|
@@ -89,6 +90,7 @@ export async function callApi(questionText, api, sessionId, action) {
|
|
|
89
90
|
};
|
|
90
91
|
const httpBody = JSON.stringify(payload);
|
|
91
92
|
const apiUrl = `${config.api.url}${API_URL_SUFFIX}`;
|
|
93
|
+
logger.log(`[SENTINEL HOOK] callApi: action=${action}, x-hag-trace-id=${sessionId}, url=${apiUrl}`);
|
|
92
94
|
return new Promise((resolve, reject) => {
|
|
93
95
|
const options = buildRequestOptions(apiUrl, headersForCelia, config.api.timeout);
|
|
94
96
|
const req = https.request(options, (res) => {
|
|
@@ -6,15 +6,16 @@ import { callApi } from './call_api.js';
|
|
|
6
6
|
import { processText, extractResultText, validateAndTruncateText, parseSecurityResult, handleExecToolInput, handleMessageToolInput, handleOtherToolInput } from './utils.js';
|
|
7
7
|
import { ALLOWED_TOOLS, MAX_TEXT_LENGTH, MAX_TOTAL_LENGTH, MIN_TEXT_LENGTH, STEER_ABORT_MESSAGE, TOOL_OUTPUT_ACTION } from './constants.js';
|
|
8
8
|
import { logger } from '../utils/logger.js';
|
|
9
|
-
import {
|
|
9
|
+
import { getCurrentSessionContext } from '../tools/session-manager.js';
|
|
10
10
|
import { tryInjectSteer } from './steer-context.js';
|
|
11
11
|
// 主入口模块
|
|
12
12
|
export default function register(api) {
|
|
13
13
|
api.on("before_tool_call", async (event, ctx) => {
|
|
14
14
|
logger.log(`[SENTINEL HOOK] before_tool_call_event toolName: ${event.toolName}`);
|
|
15
|
-
//
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
// 获取真实sessionID:优先使用ALS中的A2A sessionId,降级到OpenClaw runId或随机值
|
|
16
|
+
const sessionCtx = getCurrentSessionContext();
|
|
17
|
+
const sessionId = sessionCtx?.sessionId || (event.runId?.replace(/-/g, '') || crypto.randomBytes(16).toString('hex'));
|
|
18
|
+
logger.log(`[SENTINEL HOOK] Session ID: ${sessionId} (fromALS: ${!!sessionCtx?.sessionId})`);
|
|
18
19
|
// 处理 TOOL_INPUT 数据采集、发送数据,根据扫描结果决定是否阻塞
|
|
19
20
|
try {
|
|
20
21
|
let scanResult = null;
|
|
@@ -43,9 +44,10 @@ export default function register(api) {
|
|
|
43
44
|
}
|
|
44
45
|
try {
|
|
45
46
|
logger.log(`[SENTINEL HOOK] after_tool_call_event toolName: ${event.toolName}`);
|
|
46
|
-
//
|
|
47
|
-
const
|
|
48
|
-
|
|
47
|
+
// 获取真实sessionID:优先使用ALS中的A2A sessionId,降级到OpenClaw runId或随机值
|
|
48
|
+
const sessionCtx = getCurrentSessionContext();
|
|
49
|
+
const sessionId = sessionCtx?.sessionId || (event.runId?.replace(/-/g, '') || crypto.randomBytes(16).toString('hex'));
|
|
50
|
+
logger.log(`[SENTINEL HOOK] Session ID: ${sessionId} (fromALS: ${!!sessionCtx?.sessionId})`);
|
|
49
51
|
// 处理TOOL_OUTPUT数据采集(保持现有逻辑)
|
|
50
52
|
const resultText = extractResultText(event, event.toolName);
|
|
51
53
|
const resultTextLength = resultText.length;
|
|
@@ -78,7 +80,6 @@ export default function register(api) {
|
|
|
78
80
|
logger.log(`[SENTINEL HOOK] TOOL_OUTPUT response: status=${result.status}.`);
|
|
79
81
|
if (result.status === 'REJECT') {
|
|
80
82
|
logger.warn('[SENTINEL HOOK] REJECT detected, attempting steer injection');
|
|
81
|
-
const sessionCtx = ctx.sessionKey ? getSessionContext(ctx.sessionKey) : null;
|
|
82
83
|
if (sessionCtx?.sessionId && sessionCtx?.taskId) {
|
|
83
84
|
await tryInjectSteer({
|
|
84
85
|
sessionId: sessionCtx.sessionId,
|
package/dist/src/formatter.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// OpenClaw → A2A format conversion
|
|
2
|
+
import os from "os";
|
|
2
3
|
import { v4 as uuidv4 } from "uuid";
|
|
3
4
|
import { getXYWebSocketManager } from "./client.js";
|
|
4
5
|
import { logger } from "./utils/logger.js";
|
|
5
|
-
import { getCurrentTaskId, getCurrentMessageId } from "./task-manager.js";
|
|
6
6
|
import { redactSensitiveText, containsSensitiveInfo } from "./sensitive-redactor.js";
|
|
7
7
|
import { rewriteOutboundApprovalText } from "./approval-bridge.js";
|
|
8
8
|
import { isCronToolCall, getCurrentCronJobId } from "./tools/session-manager.js";
|
|
@@ -98,7 +98,7 @@ export async function sendA2AResponse(params) {
|
|
|
98
98
|
agentId: config.agentId,
|
|
99
99
|
sessionId,
|
|
100
100
|
taskId,
|
|
101
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
101
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
102
102
|
};
|
|
103
103
|
if (shouldLog) {
|
|
104
104
|
const redactedText = redactSensitiveText(bridgedText ?? "");
|
|
@@ -148,7 +148,7 @@ export async function sendReasoningTextUpdate(params) {
|
|
|
148
148
|
agentId: config.agentId,
|
|
149
149
|
sessionId,
|
|
150
150
|
taskId,
|
|
151
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
151
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
152
152
|
};
|
|
153
153
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
154
154
|
}
|
|
@@ -158,11 +158,7 @@ export async function sendReasoningTextUpdate(params) {
|
|
|
158
158
|
*/
|
|
159
159
|
export async function sendStatusUpdate(params) {
|
|
160
160
|
const { config, sessionId, taskId, messageId, text, state } = params;
|
|
161
|
-
|
|
162
|
-
// fall back to closure-captured values
|
|
163
|
-
const currentTaskId = getCurrentTaskId(sessionId) ?? taskId;
|
|
164
|
-
const currentMessageId = getCurrentMessageId(sessionId) ?? messageId;
|
|
165
|
-
const log = logger.withContext(sessionId, currentTaskId);
|
|
161
|
+
const log = logger.withContext(sessionId, taskId);
|
|
166
162
|
// 审批桥接和脱敏
|
|
167
163
|
const bridgedText = rewriteOutboundApprovalText(sessionId, text);
|
|
168
164
|
const redactedText = redactSensitiveText(bridgedText);
|
|
@@ -177,7 +173,7 @@ export async function sendStatusUpdate(params) {
|
|
|
177
173
|
],
|
|
178
174
|
});
|
|
179
175
|
const statusUpdate = {
|
|
180
|
-
taskId
|
|
176
|
+
taskId,
|
|
181
177
|
kind: "status-update",
|
|
182
178
|
final: false, // Status updates should not end the stream
|
|
183
179
|
status: {
|
|
@@ -188,7 +184,7 @@ export async function sendStatusUpdate(params) {
|
|
|
188
184
|
// Build JSON-RPC response
|
|
189
185
|
const jsonRpcResponse = {
|
|
190
186
|
jsonrpc: "2.0",
|
|
191
|
-
id:
|
|
187
|
+
id: messageId,
|
|
192
188
|
result: statusUpdate,
|
|
193
189
|
};
|
|
194
190
|
// Send via WebSocket
|
|
@@ -197,8 +193,8 @@ export async function sendStatusUpdate(params) {
|
|
|
197
193
|
msgType: "agent_response",
|
|
198
194
|
agentId: config.agentId,
|
|
199
195
|
sessionId,
|
|
200
|
-
taskId
|
|
201
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
196
|
+
taskId,
|
|
197
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
202
198
|
};
|
|
203
199
|
// Log complete response body
|
|
204
200
|
log.log(`[A2A_STATUS] Sending status-update, text="${redactedText}"`);
|
|
@@ -270,15 +266,11 @@ export async function sendCommand(params) {
|
|
|
270
266
|
return sendCommandViaPush({ config, command: commands[0], pushId });
|
|
271
267
|
}
|
|
272
268
|
// ── Normal mode: WebSocket ─────────────────────────────────────
|
|
273
|
-
|
|
274
|
-
// fall back to closure-captured values
|
|
275
|
-
const currentTaskId = getCurrentTaskId(sessionId) ?? taskId;
|
|
276
|
-
const currentMessageId = getCurrentMessageId(sessionId) ?? messageId;
|
|
277
|
-
const log = logger.withContext(sessionId, currentTaskId);
|
|
269
|
+
const log = logger.withContext(sessionId, taskId);
|
|
278
270
|
// Build artifact update with command as data
|
|
279
271
|
// Wrap command in commands array as per protocol requirement
|
|
280
272
|
const artifact = {
|
|
281
|
-
taskId
|
|
273
|
+
taskId,
|
|
282
274
|
kind: "artifact-update",
|
|
283
275
|
append: false,
|
|
284
276
|
lastChunk: true,
|
|
@@ -300,7 +292,7 @@ export async function sendCommand(params) {
|
|
|
300
292
|
// Build JSON-RPC response
|
|
301
293
|
const jsonRpcResponse = {
|
|
302
294
|
jsonrpc: "2.0",
|
|
303
|
-
id:
|
|
295
|
+
id: messageId,
|
|
304
296
|
result: artifact,
|
|
305
297
|
};
|
|
306
298
|
// Send via WebSocket
|
|
@@ -309,8 +301,8 @@ export async function sendCommand(params) {
|
|
|
309
301
|
msgType: "agent_response",
|
|
310
302
|
agentId: config.agentId,
|
|
311
303
|
sessionId,
|
|
312
|
-
taskId
|
|
313
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
304
|
+
taskId,
|
|
305
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
314
306
|
};
|
|
315
307
|
// Log complete response body
|
|
316
308
|
log.log(`[A2A_COMMAND] Sending command`);
|
|
@@ -329,12 +321,10 @@ export async function sendCard(params) {
|
|
|
329
321
|
throw new Error("sendCard does not support cron mode");
|
|
330
322
|
}
|
|
331
323
|
// ── Normal mode: WebSocket ─────────────────────────────────────
|
|
332
|
-
const
|
|
333
|
-
const currentMessageId = getCurrentMessageId(sessionId) ?? messageId;
|
|
334
|
-
const log = logger.withContext(sessionId, currentTaskId);
|
|
324
|
+
const log = logger.withContext(sessionId, taskId);
|
|
335
325
|
// Build artifact update with cardsInfo as data
|
|
336
326
|
const artifact = {
|
|
337
|
-
taskId
|
|
327
|
+
taskId,
|
|
338
328
|
kind: "artifact-update",
|
|
339
329
|
append: false,
|
|
340
330
|
lastChunk: true,
|
|
@@ -354,7 +344,7 @@ export async function sendCard(params) {
|
|
|
354
344
|
// Build JSON-RPC response
|
|
355
345
|
const jsonRpcResponse = {
|
|
356
346
|
jsonrpc: "2.0",
|
|
357
|
-
id:
|
|
347
|
+
id: messageId,
|
|
358
348
|
result: artifact,
|
|
359
349
|
};
|
|
360
350
|
// Send via WebSocket
|
|
@@ -363,8 +353,8 @@ export async function sendCard(params) {
|
|
|
363
353
|
msgType: "agent_response",
|
|
364
354
|
agentId: config.agentId,
|
|
365
355
|
sessionId,
|
|
366
|
-
taskId
|
|
367
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
356
|
+
taskId,
|
|
357
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
368
358
|
};
|
|
369
359
|
log.log(`[A2A_CARD] Sending card`);
|
|
370
360
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
@@ -398,7 +388,7 @@ export async function sendClearContextResponse(params) {
|
|
|
398
388
|
agentId: config.agentId,
|
|
399
389
|
sessionId,
|
|
400
390
|
taskId: sessionId, // Use sessionId as taskId for clearContext
|
|
401
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
391
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
402
392
|
};
|
|
403
393
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
404
394
|
log.log(`[CLEAR_CONTEXT] Sent clearContext response`);
|
|
@@ -432,7 +422,7 @@ export async function sendTasksCancelResponse(params) {
|
|
|
432
422
|
agentId: config.agentId,
|
|
433
423
|
sessionId,
|
|
434
424
|
taskId,
|
|
435
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
425
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
436
426
|
};
|
|
437
427
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
438
428
|
log.log(`[TASKS_CANCEL] Sent tasks/cancel response`);
|
|
@@ -480,7 +470,7 @@ export async function sendTriggerResponse(params) {
|
|
|
480
470
|
agentId: config.agentId,
|
|
481
471
|
sessionId,
|
|
482
472
|
taskId,
|
|
483
|
-
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
473
|
+
msgDetail: JSON.stringify({ ...jsonRpcResponse, hostname: os.hostname() }),
|
|
484
474
|
};
|
|
485
475
|
log.log(`[TRIGGER_RESPONSE] Sending Trigger response, text=${buildTextPreview(redactedContent)}`);
|
|
486
476
|
await wsManager.sendMessage(sessionId, outboundMessage);
|