@wu529778790/open-im 1.9.4-beta.6 → 1.9.4-beta.8

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.
@@ -1,5 +1,5 @@
1
1
  import { resolvePlatformAiCommand } from '../config.js';
2
- import { sendTextReply, startTypingLoop, sendImageReply, sendThinkingCard, streamContentUpdate, } from './message-sender.js';
2
+ import { sendTextReply, startTypingLoop, sendImageReply, sendThinkingCard, streamContentUpdate, sendFinalCards, sendErrorCard, } from './message-sender.js';
3
3
  import { buildCardV2 } from './card-builder.js';
4
4
  import { disableStreaming, updateCardFull, destroySession } from './cardkit-manager.js';
5
5
  import { CARDKIT_THROTTLE_MS } from '../constants.js';
@@ -172,33 +172,6 @@ export function setupFeishuHandlers(config, sessionManager) {
172
172
  await sendImageReply(chatId, imagePath);
173
173
  },
174
174
  };
175
- // Feishu-specific task callbacks for CardKit streaming
176
- const feishuTaskCallbacks = {
177
- streamUpdate: async (content, toolNote) => {
178
- if (consecutiveStreamErrors >= MAX_STREAM_ERRORS)
179
- return; // Stop trying
180
- const note = buildProgressNote(toolNote);
181
- // Note: cardId is passed via taskKey format: userId:cardId
182
- const cardId = content; // Placeholder, will be overridden via context
183
- streamContentUpdate(cardId, content, note).then(() => {
184
- consecutiveStreamErrors = 0;
185
- }).catch((e) => {
186
- consecutiveStreamErrors++;
187
- if (consecutiveStreamErrors >= MAX_STREAM_ERRORS) {
188
- log.warn(`Stream update failed ${consecutiveStreamErrors} times consecutively, giving up: ${e?.message ?? e}`);
189
- }
190
- else {
191
- log.debug('Stream update failed (will retry on next update):', e?.message ?? e);
192
- }
193
- });
194
- },
195
- sendComplete: async (content, note) => {
196
- // Will be customized via context
197
- },
198
- sendError: async (error) => {
199
- // Will be customized via context
200
- },
201
- };
202
175
  // Create platform-specific AI request handler
203
176
  const handleAIRequest = createPlatformAIRequestHandler({
204
177
  platform: 'feishu',
@@ -214,6 +187,30 @@ export function setupFeishuHandlers(config, sessionManager) {
214
187
  const resetCard = buildCardV2({ content: content || '...', status: 'streaming', toolName: resolvePlatformAiCommand(config, 'feishu') }, cardId);
215
188
  updateCardFull(cardId, resetCard).catch((e) => log.warn('Thinking→text transition update failed:', e?.message ?? e));
216
189
  },
190
+ taskCallbacksFactory: ({ chatId, msgId: cardId, toolId }) => ({
191
+ streamUpdate: async (content, toolNote) => {
192
+ if (consecutiveStreamErrors >= MAX_STREAM_ERRORS)
193
+ return;
194
+ const note = buildProgressNote(toolNote);
195
+ streamContentUpdate(cardId, content, note).then(() => {
196
+ consecutiveStreamErrors = 0;
197
+ }).catch((e) => {
198
+ consecutiveStreamErrors++;
199
+ if (consecutiveStreamErrors >= MAX_STREAM_ERRORS) {
200
+ log.warn(`Stream update failed ${consecutiveStreamErrors} times consecutively, giving up: ${e?.message ?? e}`);
201
+ }
202
+ else {
203
+ log.debug('Stream update failed (will retry on next update):', e?.message ?? e);
204
+ }
205
+ });
206
+ },
207
+ sendComplete: async (content, note, thinkingText) => {
208
+ await sendFinalCards(chatId, '', cardId, content, note ?? '', thinkingText, toolId);
209
+ },
210
+ sendError: async (error) => {
211
+ await sendErrorCard(cardId, error);
212
+ },
213
+ }),
217
214
  });
218
215
  /**
219
216
  * 解析 action value(兼容对象、JSON 字符串)
@@ -1,4 +1,4 @@
1
- import { sendThinkingMessage, sendTextReply, sendImageReply, sendDirectorySelection, startTypingLoop, } from "./message-sender.js";
1
+ import { sendThinkingMessage, sendFinalMessages, sendErrorMessage, sendTextReply, sendImageReply, sendDirectorySelection, startTypingLoop, } from "./message-sender.js";
2
2
  import { createLogger } from "../logger.js";
3
3
  import { buildMediaMetadataPrompt } from "../shared/media-prompt.js";
4
4
  import { buildSavedMediaBatchPrompt, buildSavedMediaPrompt } from "../shared/media-analysis-prompt.js";
@@ -153,31 +153,21 @@ export function setupQQHandlers(config, sessionManager) {
153
153
  qqTaskContextMap.delete(ctx.taskKey);
154
154
  };
155
155
  },
156
- taskCallbacks: {
157
- streamUpdate: async (content, toolNote) => {
158
- // QQ doesn't support streaming updates; this is a no-op
156
+ taskCallbacksFactory: ({ chatId, msgId, toolId }) => ({
157
+ streamUpdate: async () => {
158
+ // QQ doesn't support streaming updates
159
159
  },
160
160
  sendComplete: async (content, note) => {
161
- // QQ sends final - handled via pendingReplies in message-sender.ts
161
+ await sendFinalMessages(chatId, msgId, content, note ?? '', toolId);
162
162
  },
163
163
  sendError: async (error) => {
164
- // QQ sends error - handled via pendingReplies in message-sender.ts
164
+ await sendErrorMessage(chatId, msgId, error, toolId);
165
165
  },
166
- },
166
+ }),
167
167
  });
168
- // Wrap factory handleAIRequest to match ClaudeRequestHandler signature
169
- // (used by commandHandler.dispatch and handleTextFlow)
170
- async function handleAIRequest(userId, chatId, prompt, workDir, convId, _threadCtx, replyToMessageId, signal) {
171
- await factoryHandleAIRequest({
172
- userId,
173
- chatId,
174
- prompt,
175
- workDir,
176
- convId,
177
- replyToMessageId,
178
- signal,
179
- });
180
- }
168
+ // NOTE: handleTextFlow calls handleAIRequest with an OBJECT argument,
169
+ // so we pass factoryHandleAIRequest directly (it takes HandleAIRequestParams).
170
+ // The attachment path also uses factoryHandleAIRequest with object syntax.
181
171
  function cleanupRecentEvents(now) {
182
172
  for (const [eventId, timestamp] of recentEventIds) {
183
173
  if (now - timestamp > QQ_EVENT_DEDUP_TTL_MS) {
@@ -238,7 +228,7 @@ export function setupQQHandlers(config, sessionManager) {
238
228
  chatId,
239
229
  text,
240
230
  ctx: platformContext,
241
- handleAIRequest,
231
+ handleAIRequest: factoryHandleAIRequest,
242
232
  sendTextReply,
243
233
  workDir: sessionManager.getWorkDir(userId),
244
234
  convId: sessionManager.getConvId(userId),
@@ -266,7 +256,15 @@ export function setupQQHandlers(config, sessionManager) {
266
256
  setChatUser(chatId, userId, "qq");
267
257
  // Enqueue attachment prompt
268
258
  const enqueueResult = requestQueue.enqueue(userId, convId ?? '', attachmentPrompt, async (prompt, signal) => {
269
- await handleAIRequest(userId, chatId, prompt, workDir, convId, undefined, event.id, signal);
259
+ await factoryHandleAIRequest({
260
+ userId,
261
+ chatId,
262
+ prompt,
263
+ workDir,
264
+ convId,
265
+ replyToMessageId: event.id,
266
+ signal,
267
+ });
270
268
  });
271
269
  if (enqueueResult === "rejected") {
272
270
  await sendTextReply(chatId, "Request queue is full. Please try again later.");
@@ -143,6 +143,7 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
143
143
  throttledUpdate(taskState.latestContent, true);
144
144
  },
145
145
  onComplete: async (result) => {
146
+ log.info(`[AITask] onComplete fired: settled=${settled}, success=${result.success}, platform=${ctx.platform}, taskKey=${ctx.taskKey}`);
146
147
  if (settled)
147
148
  return;
148
149
  settled = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wu529778790/open-im",
3
- "version": "1.9.4-beta.6",
3
+ "version": "1.9.4-beta.8",
4
4
  "description": "Multi-platform IM bridge for AI CLI tools (Claude, Codex, CodeBuddy)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",