@ynhcj/xiaoyi-channel 0.0.127-beta → 0.0.128-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.d.ts +3 -6
- package/dist/index.js +71 -53
- package/dist/provider-discovery.d.ts +2 -0
- package/dist/provider-discovery.js +4 -0
- package/dist/src/bot.js +3 -0
- package/dist/src/formatter.d.ts +2 -0
- package/dist/src/formatter.js +14 -12
- package/dist/src/monitor.js +1 -0
- package/dist/src/provider.js +21 -17
- package/dist/src/reply-dispatcher.js +8 -0
- package/dist/src/utils/logger.js +20 -18
- package/openclaw.plugin.json +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
1
|
declare const _default: {
|
|
3
2
|
id: string;
|
|
4
3
|
name: string;
|
|
5
4
|
description: string;
|
|
6
|
-
configSchema: import("openclaw/plugin-sdk").
|
|
7
|
-
register: (
|
|
8
|
-
|
|
9
|
-
setChannelRuntime?: (runtime: import("openclaw/plugin-sdk").PluginRuntime) => void;
|
|
10
|
-
};
|
|
5
|
+
configSchema: import("openclaw/plugin-sdk").OpenClawPluginConfigSchema;
|
|
6
|
+
register: NonNullable<import("openclaw/plugin-sdk/core").OpenClawPluginDefinition["register"]>;
|
|
7
|
+
} & Pick<import("openclaw/plugin-sdk/core").OpenClawPluginDefinition, "kind" | "reload" | "nodeHostCommands" | "securityAuditCollectors">;
|
|
11
8
|
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { definePluginEntry } from "openclaw/plugin-sdk/core";
|
|
2
2
|
import { xiaoyiProvider } from "./src/provider.js";
|
|
3
3
|
import { xyPlugin } from "./src/channel.js";
|
|
4
4
|
import { callCsplApi } from "./src/cspl/call-api.js";
|
|
@@ -9,61 +9,79 @@ import { tryInjectSteer } from "./src/steer-injector.js";
|
|
|
9
9
|
import { registerSelfEvolutionToolResultNudge } from "./src/self-evolution-tool-result-nudge.js";
|
|
10
10
|
import { createBeforePromptBuildHandler } from "./src/skill-retriever/hooks.js";
|
|
11
11
|
import { normalizeToolRetrieverConfig } from "./src/skill-retriever/config.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (
|
|
12
|
+
function registerFullHooks(api) {
|
|
13
|
+
// SKILL RETRIEVER HOOK: before_prompt_build hook
|
|
14
|
+
const pluginConfig = api.pluginConfig || {};
|
|
15
|
+
const skillRetrieverConfig = normalizeToolRetrieverConfig({
|
|
16
|
+
enabled: pluginConfig.skillRetrieverEnabled ?? true,
|
|
17
|
+
maxTools: pluginConfig.skillRetrieverMaxTools ?? 2,
|
|
18
|
+
includeUninstalledOnly: true,
|
|
19
|
+
envFilePath: "~/.openclaw/.xiaoyienv",
|
|
20
|
+
timeoutMs: pluginConfig.skillRetrieverTimeoutMs ?? 1000,
|
|
21
|
+
});
|
|
22
|
+
const beforePromptBuildHandler = createBeforePromptBuildHandler(skillRetrieverConfig);
|
|
23
|
+
api.on("before_prompt_build", beforePromptBuildHandler);
|
|
24
|
+
registerSelfEvolutionToolResultNudge(api);
|
|
25
|
+
api.on("after_tool_call", async (event, ctx) => {
|
|
26
|
+
if (!ALLOWED_TOOLS.includes(event.toolName)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
console.log(`[SENTINEL HOOK] after_tool_call triggered: toolName=${event.toolName}, sessionKey=${ctx.sessionKey ?? "none"}`);
|
|
30
|
+
try {
|
|
31
|
+
const resultText = extractResultText(event, event.toolName);
|
|
32
|
+
const resultLength = resultText.length;
|
|
33
|
+
if (resultLength <= MIN_TEXT_LENGTH || resultLength > MAX_TOTAL_LENGTH) {
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
questionText.output[0].content = originText;
|
|
50
|
-
let finalJson = JSON.stringify(questionText);
|
|
51
|
-
if (finalJson.length > MAX_TEXT_LENGTH) {
|
|
52
|
-
const diff = finalJson.length - MAX_TEXT_LENGTH;
|
|
53
|
-
const { text: trimmed } = validateAndTruncateText(originText, MAX_TEXT_LENGTH - diff);
|
|
54
|
-
questionText.output[0].content = trimmed;
|
|
55
|
-
finalJson = JSON.stringify(questionText);
|
|
56
|
-
}
|
|
57
|
-
const response = await callCsplApi(finalJson, api.config);
|
|
58
|
-
const result = parseSecurityResult(response);
|
|
59
|
-
console.log(`[SENTINEL HOOK] Security result: status=${result.status}`);
|
|
60
|
-
if (result.status === "REJECT") {
|
|
61
|
-
await tryInjectSteer(ctx.sessionKey, STEER_ABORT_MESSAGE);
|
|
62
|
-
}
|
|
36
|
+
const questionText = {
|
|
37
|
+
subSceneID: "TOOL_OUTPUT",
|
|
38
|
+
tool: event.toolName,
|
|
39
|
+
output: [{ content: "" }],
|
|
40
|
+
};
|
|
41
|
+
const originText = processText(resultText);
|
|
42
|
+
questionText.output[0].content = originText;
|
|
43
|
+
let finalJson = JSON.stringify(questionText);
|
|
44
|
+
if (finalJson.length > MAX_TEXT_LENGTH) {
|
|
45
|
+
const diff = finalJson.length - MAX_TEXT_LENGTH;
|
|
46
|
+
const { text: trimmed } = validateAndTruncateText(originText, MAX_TEXT_LENGTH - diff);
|
|
47
|
+
questionText.output[0].content = trimmed;
|
|
48
|
+
finalJson = JSON.stringify(questionText);
|
|
63
49
|
}
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
const response = await callCsplApi(finalJson, api.config);
|
|
51
|
+
const result = parseSecurityResult(response);
|
|
52
|
+
console.log(`[SENTINEL HOOK] Security result: status=${result.status}`);
|
|
53
|
+
if (result.status === "REJECT") {
|
|
54
|
+
await tryInjectSteer(ctx.sessionKey, STEER_ABORT_MESSAGE);
|
|
66
55
|
}
|
|
67
|
-
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
api.logger.error(`[SENTINEL HOOK] after_tool_call error: ${err}`);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export default definePluginEntry({
|
|
63
|
+
id: "xiaoyi-channel",
|
|
64
|
+
name: "Xiaoyi Channel",
|
|
65
|
+
description: "Xiaoyi channel plugin - Xiaoyi A2A protocol integration",
|
|
66
|
+
register(api) {
|
|
67
|
+
// Always register the provider so wrapStreamFn/prepareExtraParams work
|
|
68
|
+
// in ALL registration modes (not just "full").
|
|
69
|
+
api.registerProvider(xiaoyiProvider);
|
|
70
|
+
if (api.registrationMode === "cli-metadata") {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (api.registrationMode === "tool-discovery") {
|
|
74
|
+
registerFullHooks(api);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Register channel plugin and set runtime
|
|
78
|
+
api.registerChannel({ plugin: xyPlugin });
|
|
79
|
+
setXYRuntime(api.runtime);
|
|
80
|
+
if (api.registrationMode === "discovery") {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (api.registrationMode === "full") {
|
|
84
|
+
registerFullHooks(api);
|
|
85
|
+
}
|
|
68
86
|
},
|
|
69
87
|
});
|
package/dist/src/bot.js
CHANGED
|
@@ -90,6 +90,7 @@ export async function handleXYMessage(params) {
|
|
|
90
90
|
text: pushDataItem.dataDetail,
|
|
91
91
|
append: false,
|
|
92
92
|
final: true,
|
|
93
|
+
runtime,
|
|
93
94
|
});
|
|
94
95
|
log(`[BOT] ✅ Trigger response sent successfully, exiting early`);
|
|
95
96
|
return; // 提前返回,不继续处理
|
|
@@ -162,6 +163,7 @@ export async function handleXYMessage(params) {
|
|
|
162
163
|
taskId: parsed.taskId,
|
|
163
164
|
messageId: parsed.messageId,
|
|
164
165
|
agentId: route.accountId,
|
|
166
|
+
deviceType,
|
|
165
167
|
});
|
|
166
168
|
// 🔑 发送初始状态更新(第二条消息也要发,用新taskId)
|
|
167
169
|
log(`[STATUS] Sending initial status update for session ${parsed.sessionId}`);
|
|
@@ -172,6 +174,7 @@ export async function handleXYMessage(params) {
|
|
|
172
174
|
messageId: parsed.messageId,
|
|
173
175
|
text: isSecondMessage ? "新消息已接收,正在处理..." : "任务正在处理中,请稍候~",
|
|
174
176
|
state: "working",
|
|
177
|
+
runtime,
|
|
175
178
|
}).catch((err) => {
|
|
176
179
|
error(`Failed to send initial status update:`, err);
|
|
177
180
|
});
|
package/dist/src/formatter.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface SendA2AResponseParams {
|
|
|
17
17
|
}>;
|
|
18
18
|
errorCode?: number | string;
|
|
19
19
|
errorMessage?: string;
|
|
20
|
+
runtime?: any;
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Send an A2A artifact update response.
|
|
@@ -49,6 +50,7 @@ export interface SendStatusUpdateParams {
|
|
|
49
50
|
messageId: string;
|
|
50
51
|
text: string;
|
|
51
52
|
state: "submitted" | "working" | "input-required" | "completed" | "canceled" | "failed" | "unknown";
|
|
53
|
+
runtime?: any;
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
54
56
|
* Send an A2A task status update.
|
package/dist/src/formatter.js
CHANGED
|
@@ -6,7 +6,8 @@ import { logger } from "./utils/logger.js";
|
|
|
6
6
|
* Send an A2A artifact update response.
|
|
7
7
|
*/
|
|
8
8
|
export async function sendA2AResponse(params) {
|
|
9
|
-
const { config, sessionId, taskId, messageId, text, append, final, files, errorCode, errorMessage } = params;
|
|
9
|
+
const { config, sessionId, taskId, messageId, text, append, final, files, errorCode, errorMessage, runtime } = params;
|
|
10
|
+
const log = runtime?.log ?? console.log;
|
|
10
11
|
// Build artifact update event
|
|
11
12
|
const artifact = {
|
|
12
13
|
taskId,
|
|
@@ -45,7 +46,7 @@ export async function sendA2AResponse(params) {
|
|
|
45
46
|
code: errorCode,
|
|
46
47
|
message: errorMessage ?? "任务执行异常,请重试",
|
|
47
48
|
};
|
|
48
|
-
|
|
49
|
+
log(`[A2A_RESPONSE] ⚠️ Including error code: ${errorCode}`);
|
|
49
50
|
}
|
|
50
51
|
// Send via WebSocket
|
|
51
52
|
const wsManager = getXYWebSocketManager(config);
|
|
@@ -57,13 +58,13 @@ export async function sendA2AResponse(params) {
|
|
|
57
58
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
58
59
|
};
|
|
59
60
|
// 📋 Log complete response body
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
log(`[A2A_RESPONSE] 📤 Sending A2A artifact-update response: taskId: ${taskId}`);
|
|
62
|
+
log(`[A2A_RESPONSE] - append: ${append}`);
|
|
63
|
+
log(`[A2A_RESPONSE] - final: ${final}`);
|
|
64
|
+
log(`[A2A_RESPONSE] - text: ${text.length <= 10 ? text : text.slice(0, 5) + '***' + text.slice(-5)}`);
|
|
65
|
+
log(`[A2A_RESPONSE] - files count: ${files?.length ?? 0}`);
|
|
65
66
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
66
|
-
|
|
67
|
+
log(`[A2A_RESPONSE] ✅ Message sent successfully`);
|
|
67
68
|
}
|
|
68
69
|
/**
|
|
69
70
|
* Send an A2A artifact-update with reasoningText part.
|
|
@@ -108,7 +109,8 @@ export async function sendReasoningTextUpdate(params) {
|
|
|
108
109
|
* Follows A2A protocol standard format with nested status object.
|
|
109
110
|
*/
|
|
110
111
|
export async function sendStatusUpdate(params) {
|
|
111
|
-
const { config, sessionId, taskId, messageId, text, state } = params;
|
|
112
|
+
const { config, sessionId, taskId, messageId, text, state, runtime } = params;
|
|
113
|
+
const log = runtime?.log ?? console.log;
|
|
112
114
|
// Build status update event following A2A protocol standard
|
|
113
115
|
const statusUpdate = {
|
|
114
116
|
taskId,
|
|
@@ -143,9 +145,9 @@ export async function sendStatusUpdate(params) {
|
|
|
143
145
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
144
146
|
};
|
|
145
147
|
// 📋 Log complete response body
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
148
|
+
log(`[A2A_STATUS] 📤 Sending A2A status-update:`);
|
|
149
|
+
log(`[A2A_STATUS] - taskId: ${taskId}`);
|
|
150
|
+
log(`[A2A_STATUS] - text: "${text}"`);
|
|
149
151
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
150
152
|
}
|
|
151
153
|
/**
|
package/dist/src/monitor.js
CHANGED
|
@@ -227,6 +227,7 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
227
227
|
text: notificationText,
|
|
228
228
|
append: false,
|
|
229
229
|
final: true,
|
|
230
|
+
runtime,
|
|
230
231
|
}).catch(err => {
|
|
231
232
|
error(`[MONITOR] Failed to send restart notification to session ${binding.sessionId}: ${String(err)}`);
|
|
232
233
|
}));
|
package/dist/src/provider.js
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
import { createHash } from "crypto";
|
|
11
11
|
import { getCurrentSessionContext } from "./tools/session-manager.js";
|
|
12
12
|
import { selfEvolutionManager } from "./utils/self-evolution-manager.js";
|
|
13
|
-
import { logger } from "./utils/logger.js";
|
|
14
13
|
// ── Retry config ──────────────────────────────────────────────
|
|
15
14
|
const RETRY_DELAYS_MS = [10_000, 20_000, 40_000, 60_000, 60_000];
|
|
16
15
|
const MAX_RETRY_ATTEMPTS = 5;
|
|
@@ -127,7 +126,7 @@ function createRetryingStream(createStream, cronJob) {
|
|
|
127
126
|
if (!hasContent && !isContent) {
|
|
128
127
|
// ── Buffer phase (no content yet) ──
|
|
129
128
|
if (event.type === "done") {
|
|
130
|
-
|
|
129
|
+
console.log(`[xiaoyiprovider] stream completed (no content), usage: input=${event.message?.usage?.input} output=${event.message?.usage?.output}`);
|
|
131
130
|
for (const b of buffer)
|
|
132
131
|
yield b;
|
|
133
132
|
resultResolve(event.message);
|
|
@@ -142,7 +141,7 @@ function createRetryingStream(createStream, cronJob) {
|
|
|
142
141
|
else {
|
|
143
142
|
// ── Streaming phase ──
|
|
144
143
|
if (!hasContent) {
|
|
145
|
-
|
|
144
|
+
console.log("[xiaoyiprovider] first content event received, switching to streaming mode");
|
|
146
145
|
hasContent = true;
|
|
147
146
|
for (const b of buffer)
|
|
148
147
|
yield b;
|
|
@@ -151,13 +150,13 @@ function createRetryingStream(createStream, cronJob) {
|
|
|
151
150
|
// The SDK calls result() when it sees done/error — if we yield first, the generator
|
|
152
151
|
// suspends and can never reach resolve, causing a permanent deadlock.
|
|
153
152
|
if (event.type === "done") {
|
|
154
|
-
|
|
153
|
+
console.log(`[xiaoyiprovider] stream completed, usage: input=${event.message?.usage?.input} output=${event.message?.usage?.output}`);
|
|
155
154
|
resultResolve(event.message);
|
|
156
155
|
yield event;
|
|
157
156
|
return;
|
|
158
157
|
}
|
|
159
158
|
if (event.type === "error") {
|
|
160
|
-
|
|
159
|
+
console.log(`[xiaoyiprovider] stream error after content: ${event.error?.errorMessage}`);
|
|
161
160
|
errorResult = event.error;
|
|
162
161
|
break; // break inner loop, proceed to retry decision
|
|
163
162
|
}
|
|
@@ -168,15 +167,15 @@ function createRetryingStream(createStream, cronJob) {
|
|
|
168
167
|
if (errorResult?.stopReason === "error" && isRetryableProviderError(errorResult.errorMessage)) {
|
|
169
168
|
if (attempt < MAX_RETRY_ATTEMPTS - 1) {
|
|
170
169
|
const delayMs = getRetryDelayMs(attempt + 1, cronJob);
|
|
171
|
-
|
|
170
|
+
console.log(`[xiaoyiprovider] retryable error (attempt ${attempt + 1}/${MAX_RETRY_ATTEMPTS}): ` +
|
|
172
171
|
`${errorResult.errorMessage} — retrying in ${delayMs}ms`);
|
|
173
172
|
await sleep(delayMs);
|
|
174
173
|
continue; // discard buffer, retry with a new stream
|
|
175
174
|
}
|
|
176
|
-
|
|
175
|
+
console.log(`[xiaoyiprovider] all ${MAX_RETRY_ATTEMPTS} retries exhausted, surfacing last error`);
|
|
177
176
|
}
|
|
178
177
|
else if (errorResult) {
|
|
179
|
-
|
|
178
|
+
console.log(`[xiaoyiprovider] non-retryable error: ${errorResult.errorMessage}`);
|
|
180
179
|
}
|
|
181
180
|
// Non-retryable or retries exhausted — yield buffered events.
|
|
182
181
|
// Resolve before yielding the terminal event to avoid the same deadlock.
|
|
@@ -196,7 +195,7 @@ function createRetryingStream(createStream, cronJob) {
|
|
|
196
195
|
return;
|
|
197
196
|
}
|
|
198
197
|
// Safety: final fallback attempt
|
|
199
|
-
|
|
198
|
+
console.log("[xiaoyiprovider] entering final fallback attempt");
|
|
200
199
|
const lastStream = await createStream();
|
|
201
200
|
for await (const event of lastStream) {
|
|
202
201
|
if (event.type === "done") {
|
|
@@ -439,6 +438,7 @@ export const xiaoyiProvider = {
|
|
|
439
438
|
* since the default agent timeout is 48 hours).
|
|
440
439
|
*/
|
|
441
440
|
wrapStreamFn: (ctx) => {
|
|
441
|
+
console.log("[xiaoyiprovider] wrapStreamFn CALLED — provider resolved by openclaw");
|
|
442
442
|
const underlying = ctx.streamFn;
|
|
443
443
|
if (!underlying)
|
|
444
444
|
return underlying;
|
|
@@ -485,13 +485,17 @@ export const xiaoyiProvider = {
|
|
|
485
485
|
}
|
|
486
486
|
}
|
|
487
487
|
// 记录输入
|
|
488
|
-
|
|
488
|
+
console.log(`[xiaoyiprovider] input messages count: ${context.messages?.length ?? 0}`);
|
|
489
489
|
if (context.systemPrompt) {
|
|
490
|
-
|
|
490
|
+
console.log(`[xiaoyiprovider] system prompt length: ${context.systemPrompt.length}`);
|
|
491
491
|
}
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
|
|
492
|
+
// Prefer deviceType from extraParams (set by prepareExtraParams).
|
|
493
|
+
// Fall back to getCurrentSessionContext() because OpenClaw caches
|
|
494
|
+
// resolvePreparedExtraParams by provider/modelId – the cache key does
|
|
495
|
+
// not include session-specific data, so deviceType may be missing
|
|
496
|
+
// from the cached extraParams even when a session is active.
|
|
497
|
+
const extraParamsDeviceType = ctx.extraParams?.[DEVICE_TYPE_KEY] || undefined;
|
|
498
|
+
const deviceType = extraParamsDeviceType ?? getCurrentSessionContext()?.deviceType;
|
|
495
499
|
// 在发送给模型前,优化 systemPrompt 结构
|
|
496
500
|
if (context.systemPrompt) {
|
|
497
501
|
let sp = context.systemPrompt;
|
|
@@ -518,11 +522,11 @@ export const xiaoyiProvider = {
|
|
|
518
522
|
sp = sp.replace('## Runtime', combined + '\n\n## Runtime');
|
|
519
523
|
}
|
|
520
524
|
}
|
|
521
|
-
|
|
525
|
+
console.log(`[xiaoyiprovider] system prompt optimized: ${beforeLen} -> ${sp.length}`);
|
|
522
526
|
context.systemPrompt = sp;
|
|
523
527
|
}
|
|
524
528
|
const selfEvolutionEnabled = await selfEvolutionManager.isEnabled();
|
|
525
|
-
|
|
529
|
+
console.log(`[selfEvolution] selfEvolution flag: ${selfEvolutionEnabled}`);
|
|
526
530
|
context.systemPrompt = applySelfEvolutionPrompt(context.systemPrompt, selfEvolutionEnabled);
|
|
527
531
|
// Append device context to systemPrompt (using pre-captured deviceType from prepareExtraParams)
|
|
528
532
|
if (deviceType) {
|
|
@@ -550,7 +554,7 @@ export const xiaoyiProvider = {
|
|
|
550
554
|
// ── Retry-capable streaming ──────────────────────────────
|
|
551
555
|
const cronJob = isCronTriggered(context.messages);
|
|
552
556
|
if (cronJob)
|
|
553
|
-
|
|
557
|
+
console.log("[xiaoyiprovider] detected cron-triggered request, using extended retry delays");
|
|
554
558
|
const makeStream = () => underlying(model, context, {
|
|
555
559
|
...options,
|
|
556
560
|
headers: {
|
|
@@ -95,6 +95,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
95
95
|
messageId: currentMessageId, // 🔑 动态messageId
|
|
96
96
|
text: "任务正在处理中,请稍候~",
|
|
97
97
|
state: "working",
|
|
98
|
+
runtime,
|
|
98
99
|
}).catch((err) => {
|
|
99
100
|
error(`Failed to send status update:`, err);
|
|
100
101
|
});
|
|
@@ -161,6 +162,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
161
162
|
messageId: currentMessageId,
|
|
162
163
|
text: "处理失败,请稍后重试",
|
|
163
164
|
state: "failed",
|
|
165
|
+
runtime,
|
|
164
166
|
});
|
|
165
167
|
}
|
|
166
168
|
catch (statusError) {
|
|
@@ -196,6 +198,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
196
198
|
messageId: currentMessageId,
|
|
197
199
|
text: "任务处理已完成~",
|
|
198
200
|
state: "completed",
|
|
201
|
+
runtime,
|
|
199
202
|
});
|
|
200
203
|
log(`[ON_IDLE] ✅ Sent completion status update`);
|
|
201
204
|
// 🔑 使用动态taskId发送最终响应
|
|
@@ -207,6 +210,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
207
210
|
text: accumulatedText,
|
|
208
211
|
append: false,
|
|
209
212
|
final: true,
|
|
213
|
+
runtime,
|
|
210
214
|
});
|
|
211
215
|
finalSent = true;
|
|
212
216
|
log(`[ON_IDLE] ✅ Sent final response with taskId=${currentTaskId}`);
|
|
@@ -226,6 +230,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
226
230
|
messageId: currentMessageId,
|
|
227
231
|
text: "任务处理中断了~",
|
|
228
232
|
state: "failed",
|
|
233
|
+
runtime,
|
|
229
234
|
});
|
|
230
235
|
log(`[ON_IDLE] ✅ Sent failure status update`);
|
|
231
236
|
await sendA2AResponse({
|
|
@@ -238,6 +243,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
238
243
|
final: true,
|
|
239
244
|
errorCode: 99921111,
|
|
240
245
|
errorMessage: "任务执行异常,请重试",
|
|
246
|
+
runtime,
|
|
241
247
|
});
|
|
242
248
|
finalSent = true;
|
|
243
249
|
log(`[ON_IDLE] ✅ Sent error response with code: 99921111`);
|
|
@@ -282,6 +288,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
282
288
|
messageId: currentMessageId,
|
|
283
289
|
text: `正在使用工具: ${toolName}...`,
|
|
284
290
|
state: "working",
|
|
291
|
+
runtime,
|
|
285
292
|
});
|
|
286
293
|
log(`[TOOL START] ✅ Sent status update for tool start: ${toolName}`);
|
|
287
294
|
}
|
|
@@ -310,6 +317,7 @@ export function createXYReplyDispatcher(params) {
|
|
|
310
317
|
messageId: currentMessageId,
|
|
311
318
|
text: resultText,
|
|
312
319
|
state: "working",
|
|
320
|
+
runtime,
|
|
313
321
|
});
|
|
314
322
|
log(`[TOOL RESULT] ✅ Sent tool result as status update`);
|
|
315
323
|
}
|
package/dist/src/utils/logger.js
CHANGED
|
@@ -1,34 +1,36 @@
|
|
|
1
1
|
// Logging utilities for XY channel
|
|
2
2
|
import { getXYRuntime } from "../runtime.js";
|
|
3
|
-
|
|
4
|
-
* Log a message using the OpenClaw runtime logger.
|
|
5
|
-
*/
|
|
6
|
-
function logMessage(level, message, ...args) {
|
|
3
|
+
function getRuntime() {
|
|
7
4
|
try {
|
|
8
|
-
|
|
9
|
-
const logFn = runtime[level];
|
|
10
|
-
if (logFn) {
|
|
11
|
-
const formattedMessage = `[XY] ${message}`;
|
|
12
|
-
logFn(formattedMessage, ...args);
|
|
13
|
-
}
|
|
5
|
+
return getXYRuntime();
|
|
14
6
|
}
|
|
15
|
-
catch
|
|
16
|
-
|
|
17
|
-
console[level](`[XY] ${message}`, ...args);
|
|
7
|
+
catch {
|
|
8
|
+
return undefined;
|
|
18
9
|
}
|
|
19
10
|
}
|
|
11
|
+
function getLog() {
|
|
12
|
+
const runtime = getRuntime();
|
|
13
|
+
return runtime?.log ?? console.log;
|
|
14
|
+
}
|
|
15
|
+
function getWarn() {
|
|
16
|
+
const runtime = getRuntime();
|
|
17
|
+
return runtime?.warn ?? console.warn;
|
|
18
|
+
}
|
|
19
|
+
function getError() {
|
|
20
|
+
const runtime = getRuntime();
|
|
21
|
+
return runtime?.error ?? console.error;
|
|
22
|
+
}
|
|
20
23
|
export const logger = {
|
|
21
24
|
log(message, ...args) {
|
|
22
|
-
|
|
25
|
+
getLog()(message, ...args);
|
|
23
26
|
},
|
|
24
27
|
warn(message, ...args) {
|
|
25
|
-
|
|
28
|
+
getWarn()(message, ...args);
|
|
26
29
|
},
|
|
27
30
|
error(message, ...args) {
|
|
28
|
-
|
|
31
|
+
getError()(message, ...args);
|
|
29
32
|
},
|
|
30
33
|
debug(message, ...args) {
|
|
31
|
-
|
|
32
|
-
logMessage("log", `[DEBUG] ${message}`, ...args);
|
|
34
|
+
getLog()(`[DEBUG] ${message}`, ...args);
|
|
33
35
|
},
|
|
34
36
|
};
|
package/openclaw.plugin.json
CHANGED