@ynhcj/xiaoyi-channel 0.0.126-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 +9 -28
- 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/dist/src/websocket.js +0 -1
- 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
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
// OpenClaw → A2A format conversion
|
|
2
2
|
import { v4 as uuidv4 } from "uuid";
|
|
3
3
|
import { getXYWebSocketManager } from "./client.js";
|
|
4
|
-
import {
|
|
4
|
+
import { logger } from "./utils/logger.js";
|
|
5
5
|
/**
|
|
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;
|
|
10
|
-
const runtime = getXYRuntime();
|
|
9
|
+
const { config, sessionId, taskId, messageId, text, append, final, files, errorCode, errorMessage, runtime } = params;
|
|
11
10
|
const log = runtime?.log ?? console.log;
|
|
12
|
-
const errorFn = runtime?.error ?? console.error;
|
|
13
11
|
// Build artifact update event
|
|
14
12
|
const artifact = {
|
|
15
13
|
taskId,
|
|
@@ -75,9 +73,6 @@ export async function sendA2AResponse(params) {
|
|
|
75
73
|
*/
|
|
76
74
|
export async function sendReasoningTextUpdate(params) {
|
|
77
75
|
const { config, sessionId, taskId, messageId, text, append = true } = params;
|
|
78
|
-
const runtime = getXYRuntime();
|
|
79
|
-
const log = runtime?.log ?? console.log;
|
|
80
|
-
const error = runtime?.error ?? console.error;
|
|
81
76
|
const artifact = {
|
|
82
77
|
taskId,
|
|
83
78
|
kind: "artifact-update",
|
|
@@ -114,10 +109,8 @@ export async function sendReasoningTextUpdate(params) {
|
|
|
114
109
|
* Follows A2A protocol standard format with nested status object.
|
|
115
110
|
*/
|
|
116
111
|
export async function sendStatusUpdate(params) {
|
|
117
|
-
const { config, sessionId, taskId, messageId, text, state } = params;
|
|
118
|
-
const runtime = getXYRuntime();
|
|
112
|
+
const { config, sessionId, taskId, messageId, text, state, runtime } = params;
|
|
119
113
|
const log = runtime?.log ?? console.log;
|
|
120
|
-
const error = runtime?.error ?? console.error;
|
|
121
114
|
// Build status update event following A2A protocol standard
|
|
122
115
|
const statusUpdate = {
|
|
123
116
|
taskId,
|
|
@@ -162,9 +155,6 @@ export async function sendStatusUpdate(params) {
|
|
|
162
155
|
*/
|
|
163
156
|
export async function sendCommand(params) {
|
|
164
157
|
const { config, sessionId, taskId, messageId, command } = params;
|
|
165
|
-
const runtime = getXYRuntime();
|
|
166
|
-
const log = runtime?.log ?? console.log;
|
|
167
|
-
const error = runtime?.error ?? console.error;
|
|
168
158
|
// Build artifact update with command as data
|
|
169
159
|
// Wrap command in commands array as per protocol requirement
|
|
170
160
|
const artifact = {
|
|
@@ -201,18 +191,15 @@ export async function sendCommand(params) {
|
|
|
201
191
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
202
192
|
};
|
|
203
193
|
// 📋 Log complete response body
|
|
204
|
-
log(`[A2A_COMMAND] 📤 Sending A2A command: taskId: ${taskId}`);
|
|
194
|
+
logger.log(`[A2A_COMMAND] 📤 Sending A2A command: taskId: ${taskId}`);
|
|
205
195
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
206
|
-
log(`[A2A_COMMAND] ✅ Command sent successfully`);
|
|
196
|
+
logger.log(`[A2A_COMMAND] ✅ Command sent successfully`);
|
|
207
197
|
}
|
|
208
198
|
/**
|
|
209
199
|
* Send a clearContext response.
|
|
210
200
|
*/
|
|
211
201
|
export async function sendClearContextResponse(params) {
|
|
212
202
|
const { config, sessionId, messageId } = params;
|
|
213
|
-
const runtime = getXYRuntime();
|
|
214
|
-
const log = runtime?.log ?? console.log;
|
|
215
|
-
const error = runtime?.error ?? console.error;
|
|
216
203
|
// Build JSON-RPC response for clearContext
|
|
217
204
|
const jsonRpcResponse = {
|
|
218
205
|
jsonrpc: "2.0",
|
|
@@ -238,16 +225,13 @@ export async function sendClearContextResponse(params) {
|
|
|
238
225
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
239
226
|
};
|
|
240
227
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
241
|
-
log(`Sent clearContext response: sessionId=${sessionId}`);
|
|
228
|
+
logger.log(`Sent clearContext response: sessionId=${sessionId}`);
|
|
242
229
|
}
|
|
243
230
|
/**
|
|
244
231
|
* Send a tasks/cancel response.
|
|
245
232
|
*/
|
|
246
233
|
export async function sendTasksCancelResponse(params) {
|
|
247
234
|
const { config, sessionId, taskId, messageId } = params;
|
|
248
|
-
const runtime = getXYRuntime();
|
|
249
|
-
const log = runtime?.log ?? console.log;
|
|
250
|
-
const error = runtime?.error ?? console.error;
|
|
251
235
|
// Build JSON-RPC response for tasks/cancel
|
|
252
236
|
// Note: Using any to bypass type check as the response format differs from standard A2A types
|
|
253
237
|
const jsonRpcResponse = {
|
|
@@ -274,16 +258,13 @@ export async function sendTasksCancelResponse(params) {
|
|
|
274
258
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
275
259
|
};
|
|
276
260
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
277
|
-
log(`Sent tasks/cancel response: sessionId=${sessionId}, taskId=${taskId}`);
|
|
261
|
+
logger.log(`Sent tasks/cancel response: sessionId=${sessionId}, taskId=${taskId}`);
|
|
278
262
|
}
|
|
279
263
|
/**
|
|
280
264
|
* Send a Trigger response with pushData content.
|
|
281
265
|
*/
|
|
282
266
|
export async function sendTriggerResponse(params) {
|
|
283
267
|
const { config, sessionId, taskId, messageId, content } = params;
|
|
284
|
-
const runtime = getXYRuntime();
|
|
285
|
-
const log = runtime?.log ?? console.log;
|
|
286
|
-
const error = runtime?.error ?? console.error;
|
|
287
268
|
// Build JSON-RPC response for Trigger
|
|
288
269
|
const jsonRpcResponse = {
|
|
289
270
|
jsonrpc: "2.0",
|
|
@@ -318,7 +299,7 @@ export async function sendTriggerResponse(params) {
|
|
|
318
299
|
taskId,
|
|
319
300
|
msgDetail: JSON.stringify(jsonRpcResponse),
|
|
320
301
|
};
|
|
321
|
-
log(`[TRIGGER_RESPONSE] Sending Trigger response: sessionId=${sessionId}, taskId=${taskId}`);
|
|
302
|
+
logger.log(`[TRIGGER_RESPONSE] Sending Trigger response: sessionId=${sessionId}, taskId=${taskId}`);
|
|
322
303
|
await wsManager.sendMessage(sessionId, outboundMessage);
|
|
323
|
-
log(`[TRIGGER_RESPONSE] Trigger response sent successfully`);
|
|
304
|
+
logger.log(`[TRIGGER_RESPONSE] Trigger response sent successfully`);
|
|
324
305
|
}
|
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/dist/src/websocket.js
CHANGED
|
@@ -114,7 +114,6 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
114
114
|
throw new Error("WebSocket not ready");
|
|
115
115
|
}
|
|
116
116
|
const messageStr = JSON.stringify(message);
|
|
117
|
-
this.log(`[WS-SEND] sessionId=${sessionId} taskId=${message.taskId} msgType=${message.msgType} len=${messageStr.length}`);
|
|
118
117
|
this.ws.send(messageStr);
|
|
119
118
|
}
|
|
120
119
|
/**
|
package/openclaw.plugin.json
CHANGED