mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix(feishu): replace console.log with runtime log for typing indicator errors (openclaw#18841) thanks @Clawborn
Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: Clawborn <135319479+Clawborn@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -24,6 +24,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Feishu/Group session routing: add configurable group session scopes (`group`, `group_sender`, `group_topic`, `group_topic_sender`) with legacy `topicSessionMode=enabled` compatibility so Feishu group conversations can isolate sessions by sender/topic as configured. (#17798)
|
||||
- Feishu/Reply-in-thread routing: add `replyInThread` config (`disabled|enabled`) for group replies, propagate `reply_in_thread` across text/card/media/streaming sends, and align topic-scoped session routing so newly created reply threads stay on the same session root. (#27325)
|
||||
- Feishu/Typing backoff: re-throw Feishu typing add/remove rate-limit and quota errors (`429`, `99991400`, `99991403`) and detect SDK non-throwing backoff responses so the typing keepalive circuit breaker can stop retries instead of looping indefinitely. (#28494)
|
||||
- Feishu/Zalo runtime logging: replace direct `console.log/error` usage in Feishu typing-indicator paths and Zalo monitor paths with runtime-gated logger calls so verbosity controls are respected while preserving typing backoff behavior. (#18841) Thanks @Clawborn.
|
||||
- Feishu/Probe status caching: cache successful `probeFeishu()` bot-info results for 10 minutes (bounded cache with per-account keying) to reduce repeated status/onboarding probe API calls, while bypassing cache for failures and exceptions. (#28907) Thanks @Glucksberg.
|
||||
- Feishu/Opus media send type: send `.opus` attachments with `msg_type: "audio"` (instead of `"media"`) so Feishu voice messages deliver correctly while `.mp4` remains `msg_type: "media"` and documents remain `msg_type: "file"`. (#28269) Thanks @Glucksberg.
|
||||
- Feishu/Mobile video media type: treat inbound `message_type: "media"` as video-equivalent for media key extraction, placeholder inference, and media download resolution so mobile-app video sends ingest correctly. (#25502) Thanks @4ier.
|
||||
|
||||
@@ -59,13 +59,18 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
||||
if (!replyToMessageId) {
|
||||
return;
|
||||
}
|
||||
typingState = await addTypingIndicator({ cfg, messageId: replyToMessageId, accountId });
|
||||
typingState = await addTypingIndicator({
|
||||
cfg,
|
||||
messageId: replyToMessageId,
|
||||
accountId,
|
||||
runtime: params.runtime,
|
||||
});
|
||||
},
|
||||
stop: async () => {
|
||||
if (!typingState) {
|
||||
return;
|
||||
}
|
||||
await removeTypingIndicator({ cfg, state: typingState, accountId });
|
||||
await removeTypingIndicator({ cfg, state: typingState, accountId, runtime: params.runtime });
|
||||
typingState = null;
|
||||
},
|
||||
onStartError: (err) =>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ClawdbotConfig } from "openclaw/plugin-sdk";
|
||||
import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
|
||||
import { resolveFeishuAccount } from "./accounts.js";
|
||||
import { createFeishuClient } from "./client.js";
|
||||
import { getFeishuRuntime } from "./runtime.js";
|
||||
|
||||
// Feishu emoji types for typing indicator
|
||||
// See: https://open.feishu.cn/document/server-docs/im-v1/message-reaction/emojis-introduce
|
||||
@@ -103,8 +104,9 @@ export async function addTypingIndicator(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
messageId: string;
|
||||
accountId?: string;
|
||||
runtime?: RuntimeEnv;
|
||||
}): Promise<TypingIndicatorState> {
|
||||
const { cfg, messageId, accountId } = params;
|
||||
const { cfg, messageId, accountId, runtime } = params;
|
||||
const account = resolveFeishuAccount({ cfg, accountId });
|
||||
if (!account.configured) {
|
||||
return { messageId, reactionId: null };
|
||||
@@ -124,9 +126,11 @@ export async function addTypingIndicator(params: {
|
||||
// instead of throwing. Detect backoff codes and throw to trip the breaker.
|
||||
const backoffCode = getBackoffCodeFromResponse(response);
|
||||
if (backoffCode !== undefined) {
|
||||
console.log(
|
||||
`[feishu] typing indicator response contains backoff code ${backoffCode}, stopping keepalive`,
|
||||
);
|
||||
if (getFeishuRuntime().logging.shouldLogVerbose()) {
|
||||
runtime?.log?.(
|
||||
`[feishu] typing indicator response contains backoff code ${backoffCode}, stopping keepalive`,
|
||||
);
|
||||
}
|
||||
throw new FeishuBackoffError(backoffCode);
|
||||
}
|
||||
|
||||
@@ -135,11 +139,15 @@ export async function addTypingIndicator(params: {
|
||||
return { messageId, reactionId };
|
||||
} catch (err) {
|
||||
if (isFeishuBackoffError(err)) {
|
||||
console.log(`[feishu] typing indicator hit rate-limit/quota, stopping keepalive`);
|
||||
if (getFeishuRuntime().logging.shouldLogVerbose()) {
|
||||
runtime?.log?.("[feishu] typing indicator hit rate-limit/quota, stopping keepalive");
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
// Silently fail for other non-critical errors (e.g. message deleted, permission issues)
|
||||
console.log(`[feishu] failed to add typing indicator: ${err}`);
|
||||
if (getFeishuRuntime().logging.shouldLogVerbose()) {
|
||||
runtime?.log?.(`[feishu] failed to add typing indicator: ${String(err)}`);
|
||||
}
|
||||
return { messageId, reactionId: null };
|
||||
}
|
||||
}
|
||||
@@ -153,8 +161,9 @@ export async function removeTypingIndicator(params: {
|
||||
cfg: ClawdbotConfig;
|
||||
state: TypingIndicatorState;
|
||||
accountId?: string;
|
||||
runtime?: RuntimeEnv;
|
||||
}): Promise<void> {
|
||||
const { cfg, state, accountId } = params;
|
||||
const { cfg, state, accountId, runtime } = params;
|
||||
if (!state.reactionId) {
|
||||
return;
|
||||
}
|
||||
@@ -177,17 +186,25 @@ export async function removeTypingIndicator(params: {
|
||||
// Check for backoff codes in non-throwing SDK responses
|
||||
const backoffCode = getBackoffCodeFromResponse(result);
|
||||
if (backoffCode !== undefined) {
|
||||
console.log(
|
||||
`[feishu] typing indicator removal response contains backoff code ${backoffCode}, stopping keepalive`,
|
||||
);
|
||||
if (getFeishuRuntime().logging.shouldLogVerbose()) {
|
||||
runtime?.log?.(
|
||||
`[feishu] typing indicator removal response contains backoff code ${backoffCode}, stopping keepalive`,
|
||||
);
|
||||
}
|
||||
throw new FeishuBackoffError(backoffCode);
|
||||
}
|
||||
} catch (err) {
|
||||
if (isFeishuBackoffError(err)) {
|
||||
console.log(`[feishu] typing indicator removal hit rate-limit/quota, stopping keepalive`);
|
||||
if (getFeishuRuntime().logging.shouldLogVerbose()) {
|
||||
runtime?.log?.(
|
||||
"[feishu] typing indicator removal hit rate-limit/quota, stopping keepalive",
|
||||
);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
// Silently fail for other non-critical errors
|
||||
console.log(`[feishu] failed to remove typing indicator: ${err}`);
|
||||
if (getFeishuRuntime().logging.shouldLogVerbose()) {
|
||||
runtime?.log?.(`[feishu] failed to remove typing indicator: ${String(err)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ function startPollingLoop(params: {
|
||||
if (err instanceof ZaloApiError && err.isPollingTimeout) {
|
||||
// no updates
|
||||
} else if (!isStopped() && !abortSignal.aborted) {
|
||||
console.error(`[${account.accountId}] Zalo polling error:`, err);
|
||||
runtime.error?.(`[${account.accountId}] Zalo polling error: ${String(err)}`);
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
}
|
||||
}
|
||||
@@ -190,10 +190,12 @@ async function processUpdate(
|
||||
);
|
||||
break;
|
||||
case "message.sticker.received":
|
||||
console.log(`[${account.accountId}] Received sticker from ${message.from.id}`);
|
||||
logVerbose(core, runtime, `[${account.accountId}] Received sticker from ${message.from.id}`);
|
||||
break;
|
||||
case "message.unsupported.received":
|
||||
console.log(
|
||||
logVerbose(
|
||||
core,
|
||||
runtime,
|
||||
`[${account.accountId}] Received unsupported message type from ${message.from.id}`,
|
||||
);
|
||||
break;
|
||||
@@ -259,7 +261,7 @@ async function handleImageMessage(
|
||||
mediaPath = saved.path;
|
||||
mediaType = saved.contentType;
|
||||
} catch (err) {
|
||||
console.error(`[${account.accountId}] Failed to download Zalo image:`, err);
|
||||
runtime.error?.(`[${account.accountId}] Failed to download Zalo image: ${String(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user