@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 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").ChannelConfigSchema;
7
- register: (api: OpenClawPluginApi) => void;
8
- channelPlugin: import("openclaw/plugin-sdk").ChannelPlugin;
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 { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
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
- export default defineChannelPluginEntry({
13
- id: "xiaoyi-channel",
14
- name: "Xiaoyi Channel",
15
- description: "Xiaoyi channel plugin - Xiaoyi A2A protocol integration",
16
- plugin: xyPlugin,
17
- setRuntime: setXYRuntime,
18
- registerFull(api) {
19
- api.registerProvider(xiaoyiProvider);
20
- // SKILL RETRIEVER HOOK: before_prompt_build hook
21
- const pluginConfig = api.pluginConfig || {};
22
- const skillRetrieverConfig = normalizeToolRetrieverConfig({
23
- enabled: pluginConfig.skillRetrieverEnabled ?? true,
24
- maxTools: pluginConfig.skillRetrieverMaxTools ?? 2,
25
- includeUninstalledOnly: true,
26
- envFilePath: "~/.openclaw/.xiaoyienv",
27
- timeoutMs: pluginConfig.skillRetrieverTimeoutMs ?? 1000,
28
- });
29
- const beforePromptBuildHandler = createBeforePromptBuildHandler(skillRetrieverConfig);
30
- api.on("before_prompt_build", beforePromptBuildHandler);
31
- registerSelfEvolutionToolResultNudge(api);
32
- api.on("after_tool_call", async (event, ctx) => {
33
- if (!ALLOWED_TOOLS.includes(event.toolName)) {
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
- console.log(`[SENTINEL HOOK] after_tool_call triggered: toolName=${event.toolName}, sessionKey=${ctx.sessionKey ?? "none"}`);
37
- try {
38
- const resultText = extractResultText(event, event.toolName);
39
- const resultLength = resultText.length;
40
- if (resultLength <= MIN_TEXT_LENGTH || resultLength > MAX_TOTAL_LENGTH) {
41
- return;
42
- }
43
- const questionText = {
44
- subSceneID: "TOOL_OUTPUT",
45
- tool: event.toolName,
46
- output: [{ content: "" }],
47
- };
48
- const originText = processText(resultText);
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
- catch (err) {
65
- api.logger.error(`[SENTINEL HOOK] after_tool_call error: ${err}`);
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
  });
@@ -0,0 +1,2 @@
1
+ import { xiaoyiProvider } from "./src/provider.js";
2
+ export default xiaoyiProvider;
@@ -0,0 +1,4 @@
1
+ // Provider discovery entry for fast-path provider resolution.
2
+ // Exported as default so normalizeDiscoveryModule can unwrap it via .default.
3
+ import { xiaoyiProvider } from "./src/provider.js";
4
+ export default xiaoyiProvider;
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
  });
@@ -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.
@@ -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
- logger.log(`[A2A_RESPONSE] ⚠️ Including error code: ${errorCode}`);
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
- logger.log(`[A2A_RESPONSE] 📤 Sending A2A artifact-update response: taskId: ${taskId}`);
61
- logger.log(`[A2A_RESPONSE] - append: ${append}`);
62
- logger.log(`[A2A_RESPONSE] - final: ${final}`);
63
- logger.log(`[A2A_RESPONSE] - text: ${text.length <= 10 ? text : text.slice(0, 5) + '***' + text.slice(-5)}`);
64
- logger.log(`[A2A_RESPONSE] - files count: ${files?.length ?? 0}`);
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
- logger.log(`[A2A_RESPONSE] ✅ Message sent successfully`);
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
- logger.log(`[A2A_STATUS] 📤 Sending A2A status-update:`);
147
- logger.log(`[A2A_STATUS] - taskId: ${taskId}`);
148
- logger.log(`[A2A_STATUS] - text: "${text}"`);
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
  /**
@@ -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
  }));
@@ -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
- logger.log(`[xiaoyiprovider] stream completed (no content), usage: input=${event.message?.usage?.input} output=${event.message?.usage?.output}`);
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
- logger.log("[xiaoyiprovider] first content event received, switching to streaming mode");
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
- logger.log(`[xiaoyiprovider] stream completed, usage: input=${event.message?.usage?.input} output=${event.message?.usage?.output}`);
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
- logger.log(`[xiaoyiprovider] stream error after content: ${event.error?.errorMessage}`);
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
- logger.log(`[xiaoyiprovider] retryable error (attempt ${attempt + 1}/${MAX_RETRY_ATTEMPTS}): ` +
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
- logger.log(`[xiaoyiprovider] all ${MAX_RETRY_ATTEMPTS} retries exhausted, surfacing last error`);
175
+ console.log(`[xiaoyiprovider] all ${MAX_RETRY_ATTEMPTS} retries exhausted, surfacing last error`);
177
176
  }
178
177
  else if (errorResult) {
179
- logger.log(`[xiaoyiprovider] non-retryable error: ${errorResult.errorMessage}`);
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
- logger.log("[xiaoyiprovider] entering final fallback attempt");
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
- logger.log(`[xiaoyiprovider] input messages count: ${context.messages?.length ?? 0}`);
488
+ console.log(`[xiaoyiprovider] input messages count: ${context.messages?.length ?? 0}`);
489
489
  if (context.systemPrompt) {
490
- logger.log(`[xiaoyiprovider] system prompt length: ${context.systemPrompt.length}`);
490
+ console.log(`[xiaoyiprovider] system prompt length: ${context.systemPrompt.length}`);
491
491
  }
492
- // Reuse deviceType from extraParams instead of calling getCurrentSessionContext()
493
- // again (which may be ambiguous in multi-session or async scenarios).
494
- const deviceType = ctx.extraParams?.[DEVICE_TYPE_KEY] || undefined;
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
- logger.log(`[xiaoyiprovider] system prompt optimized: ${beforeLen} -> ${sp.length}`);
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
- logger.log(`[selfEvolution] selfEvolution flag: ${selfEvolutionEnabled}`);
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
- logger.log("[xiaoyiprovider] detected cron-triggered request, using extended retry delays");
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
  }
@@ -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
- const runtime = getXYRuntime();
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 (error) {
16
- // Fallback to console if runtime not available
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
- logMessage("log", message, ...args);
25
+ getLog()(message, ...args);
23
26
  },
24
27
  warn(message, ...args) {
25
- logMessage("warn", message, ...args);
28
+ getWarn()(message, ...args);
26
29
  },
27
30
  error(message, ...args) {
28
- logMessage("error", message, ...args);
31
+ getError()(message, ...args);
29
32
  },
30
33
  debug(message, ...args) {
31
- // Debug messages go to log level
32
- logMessage("log", `[DEBUG] ${message}`, ...args);
34
+ getLog()(`[DEBUG] ${message}`, ...args);
33
35
  },
34
36
  };
@@ -2,6 +2,7 @@
2
2
  "id": "xiaoyi-channel",
3
3
  "channels": ["xiaoyi-channel"],
4
4
  "providers": ["xiaoyiprovider"],
5
+ "providerDiscoveryEntry": "./dist/provider-discovery.js",
5
6
  "skills": [],
6
7
  "configSchema": {
7
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.127-beta",
3
+ "version": "0.0.128-beta",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",