@wu529778790/open-im 1.10.1-beta.0 → 1.10.2-beta.0

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.
@@ -509,8 +509,8 @@ async function probeWorkBuddy(config) {
509
509
  if (!accessToken || !refreshToken || !userId)
510
510
  throw new Error("WorkBuddy access token, refresh token, and user ID are required.");
511
511
  const baseUrl = clean(String(config.baseUrl ?? "")) || "https://copilot.tencent.com";
512
- // Validate credentials by attempting to register workspace
513
- const response = await fetch(`${baseUrl}/api/copilot/workspace/register`, {
512
+ // Validate credentials by attempting to register workspace (same endpoint as runtime)
513
+ const response = await fetch(`${baseUrl}/v2/agentos/localagent/registerWorkspace`, {
514
514
  method: "POST",
515
515
  headers: {
516
516
  "content-type": "application/json",
@@ -521,6 +521,7 @@ async function probeWorkBuddy(config) {
521
521
  hostId: "open-im-test",
522
522
  workspaceId: "open-im-test-workspace",
523
523
  workspaceName: "OpenIM Test Workspace",
524
+ localAgentType: "ide",
524
525
  }),
525
526
  signal: AbortSignal.timeout(TEST_TIMEOUT_MS),
526
527
  });
@@ -217,7 +217,7 @@ export function setupDingTalkHandlers(config, sessionManager) {
217
217
  const text = message.msgtype === 'text' ? message.text?.content?.trim() ?? '' : '';
218
218
  log.info(`[MSG] DingTalk message: type=${message.msgtype}, user=${userId}, chat=${chatId}`);
219
219
  if (!accessControl.isAllowed(userId)) {
220
- await sendTextReply(chatId, `Access denied. Your DingTalk user ID: ${userId}`);
220
+ await sendTextReply(chatId, `抱歉,您没有访问权限。\n您的 ID: ${userId}`);
221
221
  ackMessage(callbackId, { denied: true });
222
222
  return;
223
223
  }
@@ -247,10 +247,10 @@ export function setupDingTalkHandlers(config, sessionManager) {
247
247
  }
248
248
  const enqueueResult = await enqueuePrompt(userId, chatId, prompt, dingtalkTarget);
249
249
  if (enqueueResult === 'rejected') {
250
- await sendTextReply(chatId, 'Request queue is full. Please try again later.');
250
+ await sendTextReply(chatId, '请求队列已满,请稍后再试。');
251
251
  }
252
252
  else if (enqueueResult === 'queued') {
253
- await sendTextReply(chatId, 'Your request is queued.');
253
+ await sendTextReply(chatId, '您的请求已排队等待。');
254
254
  }
255
255
  ackMessage(callbackId, { queued: enqueueResult, kind });
256
256
  return;
@@ -273,10 +273,10 @@ export function setupDingTalkHandlers(config, sessionManager) {
273
273
  }
274
274
  const enqueueResult = await enqueuePrompt(userId, chatId, text, dingtalkTarget);
275
275
  if (enqueueResult === 'rejected') {
276
- await sendTextReply(chatId, 'Request queue is full. Please try again later.');
276
+ await sendTextReply(chatId, '请求队列已满,请稍后再试。');
277
277
  }
278
278
  else if (enqueueResult === 'queued') {
279
- await sendTextReply(chatId, 'Your request is queued.');
279
+ await sendTextReply(chatId, '您的请求已排队等待。');
280
280
  }
281
281
  ackMessage(callbackId, { queued: enqueueResult });
282
282
  }
@@ -322,12 +322,12 @@ export function setupFeishuHandlers(config, sessionManager) {
322
322
  await handleAIRequest({ userId: senderId, chatId, prompt: p, workDir: work, convId, replyToMessageId: messageId, signal });
323
323
  });
324
324
  if (enqueueResult === 'rejected') {
325
- sendTextReply(chatId, 'Request queue is full. Please try again later.').catch((sendErr) => {
325
+ sendTextReply(chatId, '请求队列已满,请稍后再试。').catch((sendErr) => {
326
326
  log.warn('[feishu] Failed to send queue full message for image:', sendErr);
327
327
  });
328
328
  }
329
329
  else if (enqueueResult === 'queued') {
330
- sendTextReply(chatId, 'Your request is queued.').catch((sendErr) => {
330
+ sendTextReply(chatId, '您的请求已排队等待。').catch((sendErr) => {
331
331
  log.warn('[feishu] Failed to send queued message for image:', sendErr);
332
332
  });
333
333
  }
@@ -370,12 +370,12 @@ export function setupFeishuHandlers(config, sessionManager) {
370
370
  await handleAIRequest({ userId: senderId, chatId, prompt: p, workDir, convId, replyToMessageId: messageId, signal });
371
371
  });
372
372
  if (enqueueResult === 'rejected') {
373
- sendTextReply(chatId, 'Request queue is full. Please try again later.').catch((sendErr) => {
373
+ sendTextReply(chatId, '请求队列已满,请稍后再试。').catch((sendErr) => {
374
374
  log.warn(`[feishu] Failed to send queue full message for ${msgType}:`, sendErr);
375
375
  });
376
376
  }
377
377
  else if (enqueueResult === 'queued') {
378
- sendTextReply(chatId, 'Your request is queued.').catch((sendErr) => {
378
+ sendTextReply(chatId, '您的请求已排队等待。').catch((sendErr) => {
379
379
  log.warn(`[feishu] Failed to send queued message for ${msgType}:`, sendErr);
380
380
  });
381
381
  }
@@ -233,9 +233,9 @@ export function setupQQHandlers(config, sessionManager) {
233
233
  workDir: sessionManager.getWorkDir(userId),
234
234
  convId: sessionManager.getConvId(userId),
235
235
  replyToMessageId: event.id,
236
- accessDeniedMessage: (userId) => `Access denied. Your QQ user ID: ${userId}`,
237
- queueFullMessage: "Request queue is full. Please try again later.",
238
- queuedMessage: "Your request is queued.",
236
+ accessDeniedMessage: (userId) => `抱歉,您没有访问权限。\n您的 ID: ${userId}`,
237
+ queueFullMessage: "请求队列已满,请稍后再试。",
238
+ queuedMessage: "您的请求已排队等待。",
239
239
  });
240
240
  if (processed) {
241
241
  log.info(`QQ message handled: user=${userId}, chat=${chatId}, text=true`);
@@ -248,7 +248,7 @@ export function setupQQHandlers(config, sessionManager) {
248
248
  const convId = sessionManager.getConvId(userId);
249
249
  // Check access control
250
250
  if (!accessControl.isAllowed(userId)) {
251
- await sendTextReply(chatId, `Access denied. Your QQ user ID: ${userId}`);
251
+ await sendTextReply(chatId, `抱歉,您没有访问权限。\n您的 ID: ${userId}`);
252
252
  return;
253
253
  }
254
254
  // Set active chat
@@ -267,10 +267,10 @@ export function setupQQHandlers(config, sessionManager) {
267
267
  });
268
268
  });
269
269
  if (enqueueResult === "rejected") {
270
- await sendTextReply(chatId, "Request queue is full. Please try again later.");
270
+ await sendTextReply(chatId, "请求队列已满,请稍后再试。");
271
271
  }
272
272
  else if (enqueueResult === "queued") {
273
- await sendTextReply(chatId, "Your request is queued.");
273
+ await sendTextReply(chatId, "您的请求已排队等待。");
274
274
  }
275
275
  log.info(`QQ message handled: user=${userId}, chat=${chatId}, attachments=${event.attachments?.length ?? 0}`);
276
276
  }
@@ -279,7 +279,7 @@ export function setupQQHandlers(config, sessionManager) {
279
279
  log.error('Unhandled error in QQ event handler:', err);
280
280
  try {
281
281
  if (chatId) {
282
- await sendTextReply(chatId, 'Internal error occurred. Please try again.');
282
+ await sendTextReply(chatId, '内部错误,请重试。');
283
283
  }
284
284
  }
285
285
  catch { /* ignore */ }
@@ -303,7 +303,7 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
303
303
  catch (err) {
304
304
  log.error('Unhandled error in Telegram text handler:', err);
305
305
  try {
306
- await tgCtx.reply('Internal error occurred. Please try again.');
306
+ await tgCtx.reply('内部错误,请重试。');
307
307
  }
308
308
  catch { /* ignore */ }
309
309
  }
@@ -333,10 +333,10 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
333
333
  }
334
334
  const enqueueResult = await enqueueSavedMedia(userId, chatId, "image", imagePath, contextText);
335
335
  if (enqueueResult === "rejected") {
336
- await sendTextReply(chatId, "Request queue is full. Please try again later.");
336
+ await sendTextReply(chatId, "请求队列已满,请稍后再试。");
337
337
  }
338
338
  else if (enqueueResult === "queued") {
339
- await sendTextReply(chatId, "Your request is queued.");
339
+ await sendTextReply(chatId, "您的请求已排队等待。");
340
340
  }
341
341
  });
342
342
  bot.on(message("document"), async (ctx) => {
@@ -357,15 +357,15 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
357
357
  const path = await downloadTelegramFile(bot, document.file_id, document.file_name ?? document.file_id, "bin");
358
358
  const enqueueResult = await enqueueSavedMedia(userId, chatId, "document", path, contextText);
359
359
  if (enqueueResult === "rejected") {
360
- await sendTextReply(chatId, "Request queue is full. Please try again later.");
360
+ await sendTextReply(chatId, "请求队列已满,请稍后再试。");
361
361
  }
362
362
  else if (enqueueResult === "queued") {
363
- await sendTextReply(chatId, "Your request is queued.");
363
+ await sendTextReply(chatId, "您的请求已排队等待。");
364
364
  }
365
365
  }
366
366
  catch (err) {
367
367
  log.error("Failed to download document:", err);
368
- await sendTextReply(chatId, "Document download failed.");
368
+ await sendTextReply(chatId, "文档下载失败。");
369
369
  }
370
370
  });
371
371
  bot.on(message("audio"), async (ctx) => {
@@ -388,15 +388,15 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
388
388
  const path = await downloadTelegramFile(bot, audio.file_id, audio.file_name ?? audio.file_id, "mp3");
389
389
  const enqueueResult = await enqueueSavedMedia(userId, chatId, "audio", path, contextText);
390
390
  if (enqueueResult === "rejected") {
391
- await sendTextReply(chatId, "Request queue is full. Please try again later.");
391
+ await sendTextReply(chatId, "请求队列已满,请稍后再试。");
392
392
  }
393
393
  else if (enqueueResult === "queued") {
394
- await sendTextReply(chatId, "Your request is queued.");
394
+ await sendTextReply(chatId, "您的请求已排队等待。");
395
395
  }
396
396
  }
397
397
  catch (err) {
398
398
  log.error("Failed to download audio:", err);
399
- await sendTextReply(chatId, "Audio download failed.");
399
+ await sendTextReply(chatId, "音频下载失败。");
400
400
  }
401
401
  });
402
402
  bot.on(message("voice"), async (ctx) => {
@@ -415,15 +415,15 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
415
415
  const path = await downloadTelegramFile(bot, voice.file_id, voice.file_unique_id ?? voice.file_id, "ogg");
416
416
  const enqueueResult = await enqueueSavedMedia(userId, chatId, "voice", path, contextText);
417
417
  if (enqueueResult === "rejected") {
418
- await sendTextReply(chatId, "Request queue is full. Please try again later.");
418
+ await sendTextReply(chatId, "请求队列已满,请稍后再试。");
419
419
  }
420
420
  else if (enqueueResult === "queued") {
421
- await sendTextReply(chatId, "Your request is queued.");
421
+ await sendTextReply(chatId, "您的请求已排队等待。");
422
422
  }
423
423
  }
424
424
  catch (err) {
425
425
  log.error("Failed to download voice message:", err);
426
- await sendTextReply(chatId, "Voice download failed.");
426
+ await sendTextReply(chatId, "语音下载失败。");
427
427
  }
428
428
  });
429
429
  bot.on(message("video"), async (ctx) => {
@@ -446,15 +446,15 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
446
446
  const path = await downloadTelegramFile(bot, video.file_id, video.file_name ?? video.file_unique_id ?? video.file_id, "mp4");
447
447
  const enqueueResult = await enqueueSavedMedia(userId, chatId, "video", path, contextText);
448
448
  if (enqueueResult === "rejected") {
449
- await sendTextReply(chatId, "Request queue is full. Please try again later.");
449
+ await sendTextReply(chatId, "请求队列已满,请稍后再试。");
450
450
  }
451
451
  else if (enqueueResult === "queued") {
452
- await sendTextReply(chatId, "Your request is queued.");
452
+ await sendTextReply(chatId, "您的请求已排队等待。");
453
453
  }
454
454
  }
455
455
  catch (err) {
456
456
  log.error("Failed to download video:", err);
457
- await sendTextReply(chatId, "Video download failed.");
457
+ await sendTextReply(chatId, "视频下载失败。");
458
458
  }
459
459
  });
460
460
  return {
@@ -202,7 +202,7 @@ export function setupWeWorkHandlers(config, sessionManager) {
202
202
  await sendFinalMessages(ctx.chatId, ctx.msgId, content, note ?? '', ctx.toolId, senderCtx.reqId);
203
203
  },
204
204
  sendError: async (error) => {
205
- await updateMessage(ctx.chatId, ctx.msgId, `Error: ${error}`, 'error', buildErrorNote(), ctx.toolId, senderCtx.reqId);
205
+ await updateMessage(ctx.chatId, ctx.msgId, `错误:${error}`, 'error', buildErrorNote(), ctx.toolId, senderCtx.reqId);
206
206
  },
207
207
  });
208
208
  // WeWork-specific init for safety timeout
@@ -244,10 +244,10 @@ export function setupWeWorkHandlers(config, sessionManager) {
244
244
  await handleAIRequest({ userId, chatId, prompt: nextPrompt, workDir, convId, replyToMessageId: undefined, signal });
245
245
  });
246
246
  if (enqueueResult === 'rejected') {
247
- await sendTextReply(chatId, 'Request queue is full. Please try again later.', reqId);
247
+ await sendTextReply(chatId, '请求队列已满,请稍后再试。', reqId);
248
248
  }
249
249
  else if (enqueueResult === 'queued') {
250
- await sendTextReply(chatId, 'Your request is queued.', reqId);
250
+ await sendTextReply(chatId, '您的请求已排队等待。', reqId);
251
251
  }
252
252
  }
253
253
  async function handleEvent(data) {
@@ -263,7 +263,7 @@ export function setupWeWorkHandlers(config, sessionManager) {
263
263
  // Check access control
264
264
  if (!ctx.accessControl.isAllowed(fromUser)) {
265
265
  log.warn(`Access denied for sender: ${fromUser}`);
266
- await sendTextReply(chatId, `Access denied. Your WeWork user ID: ${fromUser}`, reqId);
266
+ await sendTextReply(chatId, `抱歉,您没有访问权限。\n您的 ID: ${fromUser}`, reqId);
267
267
  return;
268
268
  }
269
269
  setActiveChatId('wework', chatId);
@@ -22,10 +22,10 @@ function getReqId(explicitReqId) {
22
22
  return explicitReqId;
23
23
  }
24
24
  const STATUS_CONFIG = {
25
- thinking: { icon: '[thinking]', title: '思考中' },
26
- streaming: { icon: '[streaming]', title: '输出中' },
27
- done: { icon: '[done]', title: '完成' },
28
- error: { icon: '[error]', title: '错误' },
25
+ thinking: { icon: '🔵', title: '思考中' },
26
+ streaming: { icon: '🔄', title: '输出中' },
27
+ done: { icon: '', title: '完成' },
28
+ error: { icon: '', title: '错误' },
29
29
  };
30
30
  function getToolTitle(toolId, status) {
31
31
  return buildMessageTitle(toolId, status, {
@@ -84,7 +84,7 @@ function formatWeWorkMessage(title, content, status, note) {
84
84
  message += `${content}\n\n`;
85
85
  }
86
86
  else if (status === 'thinking') {
87
- message += `_正在思考,请稍候..._\n\n[thinking] **准备中**\n\n`;
87
+ message += `_正在思考,请稍候..._\n\n🔵 **准备中**\n\n`;
88
88
  }
89
89
  if (note) {
90
90
  message += formatWeWorkNote(note);
@@ -135,7 +135,7 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
135
135
  // Access control check
136
136
  if (!ctx.accessControl.isAllowed(userId)) {
137
137
  log.warn(`Access denied for sender: ${userId}`);
138
- await sendErrorReply(null, chatId, `Access denied. Your chat ID: ${userId}`, msgId);
138
+ await sendErrorReply(null, chatId, `抱歉,您没有访问权限。\n您的 ID: ${userId}`, msgId);
139
139
  return;
140
140
  }
141
141
  setActiveChatId('workbuddy', chatId);
@@ -177,10 +177,10 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
177
177
  await handleAIRequest(userId, chatId, msgId, nextPrompt, workDir, convId, signal);
178
178
  });
179
179
  if (enqueueResult === 'rejected') {
180
- await sendErrorReply(null, chatId, 'Request queue is full. Please try again later.', msgId);
180
+ await sendErrorReply(null, chatId, '请求队列已满,请稍后再试。', msgId);
181
181
  }
182
182
  else if (enqueueResult === 'queued') {
183
- await sendTextReply(null, chatId, 'Your request is queued.', msgId);
183
+ await sendTextReply(null, chatId, '您的请求已排队等待。', msgId);
184
184
  }
185
185
  }
186
186
  return {
@@ -2,6 +2,8 @@
2
2
  * WorkBuddy OAuth - CodeBuddy authentication for WeChat KF integration
3
3
  */
4
4
  import { hostname } from 'node:os';
5
+ import { createLogger } from '../logger.js';
6
+ const log = createLogger('WorkBuddyOAuth');
5
7
  const DEFAULT_BASE_URL = 'https://copilot.tencent.com';
6
8
  const PLATFORM = 'ide';
7
9
  export class WorkBuddyOAuth {
@@ -196,7 +198,14 @@ export class WorkBuddyOAuth {
196
198
  return { success: false, message: `获取链接失败: ${res.status} ${body}` };
197
199
  }
198
200
  const body = (await res.json());
199
- return body.data ?? { success: false, message: 'Empty response' };
201
+ log.debug('getWeChatKfLink response:', JSON.stringify(body).slice(0, 500));
202
+ if (body.data)
203
+ return body.data;
204
+ // API may return fields directly without data wrapper
205
+ if (body.success !== undefined || body.url !== undefined) {
206
+ return body;
207
+ }
208
+ return { success: false, message: `Empty response: ${JSON.stringify(body).slice(0, 200)}` };
200
209
  }
201
210
  /**
202
211
  * Check WeChat KF binding status
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wu529778790/open-im",
3
- "version": "1.10.1-beta.0",
3
+ "version": "1.10.2-beta.0",
4
4
  "description": "Multi-platform IM bridge for AI CLI tools (Claude, Codex, CodeBuddy)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",