























@@ -24,6 +24,9 @@ type IMessageApprovalReactionResolution = {
2424approvalId: string;
2525decision: ExecApprovalReplyDecision;
2626};
27+export type IMessageApprovalReactionHandleResult =
28+| { handled: false; stopPolling: false }
29+| { handled: true; stopPolling: boolean };
27302831type IMessageApprovalReactionTarget = ApprovalReactionTargetRecord;
2932@@ -469,25 +472,25 @@ function readApprovalReactionEvent(
469472};
470473}
471474472-export async function maybeResolveIMessageApprovalReaction(params: {
475+export async function handleIMessageApprovalReaction(params: {
473476cfg: OpenClawConfig;
474477accountId: string;
475478message: IMessagePayload;
476479bodyText: string;
477480gatewayUrl?: string;
478481logVerboseMessage?: (message: string) => void;
479-}): Promise<boolean> {
482+}): Promise<IMessageApprovalReactionHandleResult> {
480483const event = readApprovalReactionEvent(params.message, params.bodyText);
481484if (!event) {
482-return false;
485+return { handled: false, stopPolling: false };
483486}
484487// A removed tapback (user un-taps 👍 or switches to a different emoji) is
485488// intentionally NOT a fresh resolve. We only want to clear the binding so
486489// the next added-tapback resolves freshly. Falling through to `return false`
487490// would surface the un-tap as a noisy reaction system event; instead we
488491// own the event and stay quiet.
489492if (event.action === "removed") {
490-return false;
493+return { handled: false, stopPolling: false };
491494}
492495let target: IMessageApprovalReactionResolution | null = null;
493496let matchedMessageId: string | null = null;
@@ -504,7 +507,7 @@ export async function maybeResolveIMessageApprovalReaction(params: {
504507}
505508}
506509if (!target) {
507-return false;
510+return { handled: false, stopPolling: false };
508511}
509512510513const approvalKind = target.approvalId.startsWith("plugin:") ? "plugin" : "exec";
@@ -513,7 +516,7 @@ export async function maybeResolveIMessageApprovalReaction(params: {
513516params.logVerboseMessage?.(
514517`imessage: approval reaction denied id=${target.approvalId}; reactions require explicit approvers`,
515518);
516-return true;
519+return { handled: true, stopPolling: false };
517520}
518521const auth = imessageApprovalAuth.authorizeActorAction({
519522cfg: params.cfg,
@@ -526,7 +529,7 @@ export async function maybeResolveIMessageApprovalReaction(params: {
526529params.logVerboseMessage?.(
527530`imessage: approval reaction denied id=${target.approvalId} sender=${event.actorHandle}`,
528531);
529-return true;
532+return { handled: true, stopPolling: false };
530533}
531534532535const { isApprovalNotFoundError, resolveIMessageApproval } = await loadApprovalResolver();
@@ -552,7 +555,7 @@ export async function maybeResolveIMessageApprovalReaction(params: {
552555params.logVerboseMessage?.(
553556`imessage: approval reaction resolved id=${target.approvalId} sender=${event.actorHandle} decision=${target.decision} via messageId=${matchedMessageId ?? event.messageId}`,
554557);
555-return true;
558+return { handled: true, stopPolling: true };
556559} catch (error) {
557560if (isApprovalNotFoundError(error)) {
558561for (const candidate of event.messageIdCandidates) {
@@ -565,7 +568,7 @@ export async function maybeResolveIMessageApprovalReaction(params: {
565568params.logVerboseMessage?.(
566569`imessage: approval reaction ignored for expired approval id=${target.approvalId} sender=${event.actorHandle}`,
567570);
568-return true;
571+return { handled: true, stopPolling: true };
569572}
570573// Surface non-NotFound errors at warn level so a gateway 5xx / network
571574// outage / auth failure is visible without OPENCLAW_LOG_LEVEL=debug.
@@ -583,10 +586,21 @@ export async function maybeResolveIMessageApprovalReaction(params: {
583586params.logVerboseMessage?.(
584587`imessage: approval reaction failed id=${target.approvalId} sender=${event.actorHandle}: ${String(error)}`,
585588);
586-return true;
589+return { handled: true, stopPolling: true };
587590}
588591}
589592593+export async function maybeResolveIMessageApprovalReaction(params: {
594+cfg: OpenClawConfig;
595+accountId: string;
596+message: IMessagePayload;
597+bodyText: string;
598+gatewayUrl?: string;
599+logVerboseMessage?: (message: string) => void;
600+}): Promise<boolean> {
601+return (await handleIMessageApprovalReaction(params)).handled;
602+}
603+590604export function clearIMessageApprovalReactionTargetsForTest(): void {
591605imessageApprovalReactionTargets.clearForTest();
592606pendingReactionPollTargets.clear();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。