mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
fix(replies): keep approval-unavailable notices durable (#121179)
Punchcard-Session: clear-lantern-summit-v2
This commit is contained in:
@@ -2671,6 +2671,15 @@ describe("sendPolicy deny — suppress delivery, not processing (#53328)", () =>
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "unavailable exec approvals",
|
||||
payload: {
|
||||
text: "Exec approval is unavailable.",
|
||||
channelData: {
|
||||
execApprovalUnavailable: { reason: "no-approval-route" },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "ask-user prompts",
|
||||
payload: {
|
||||
|
||||
@@ -51,6 +51,10 @@ export function hasExecApprovalPayload(payload: ReplyPayload): boolean {
|
||||
return isRecord(payload.channelData?.execApproval);
|
||||
}
|
||||
|
||||
export function hasExecApprovalUnavailablePayload(payload: ReplyPayload): boolean {
|
||||
return isRecord(payload.channelData?.execApprovalUnavailable);
|
||||
}
|
||||
|
||||
export function hasAskUserPayload(payload: ReplyPayload): boolean {
|
||||
return isRecord(payload.channelData?.askUser);
|
||||
}
|
||||
@@ -59,6 +63,7 @@ export function requiresDurableToolResultDelivery(payload: ReplyPayload): boolea
|
||||
return (
|
||||
resolveSendableOutboundReplyParts(payload).hasMedia ||
|
||||
hasExecApprovalPayload(payload) ||
|
||||
hasExecApprovalUnavailablePayload(payload) ||
|
||||
hasAskUserPayload(payload)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,11 @@ import { normalizeMessageChannel } from "../../utils/message-channel.js";
|
||||
import type { GetReplyOptions } from "../get-reply-options.types.js";
|
||||
import type { ReplyPayload } from "../reply-payload.js";
|
||||
import type { ChooseDispatchRouteReadyState } from "./dispatch-from-config.choose-route.js";
|
||||
import { hasAskUserPayload, hasExecApprovalPayload } from "./dispatch-from-config.payloads.js";
|
||||
import {
|
||||
hasAskUserPayload,
|
||||
hasExecApprovalPayload,
|
||||
hasExecApprovalUnavailablePayload,
|
||||
} from "./dispatch-from-config.payloads.js";
|
||||
import { extendPreparedDispatchState } from "./dispatch-from-config.phase-state.js";
|
||||
import { loadGetReplyFromConfigRuntime } from "./dispatch-from-config.runtime-loaders.js";
|
||||
import { withFullRuntimeReplyConfig } from "./get-reply-fast-path.js";
|
||||
@@ -121,7 +125,7 @@ export async function prepareDispatchExecution(state: ChooseDispatchRouteReadySt
|
||||
if (shouldSendToolSummaries()) {
|
||||
return payload;
|
||||
}
|
||||
if (hasExecApprovalPayload(payload)) {
|
||||
if (hasExecApprovalPayload(payload) || hasExecApprovalUnavailablePayload(payload)) {
|
||||
return payload;
|
||||
}
|
||||
if (hasAskUserPayload(payload)) {
|
||||
|
||||
@@ -427,6 +427,31 @@ describe("dispatchReplyFromConfig", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("delivers approval-unavailable notices when verbose tool progress is disabled", async () => {
|
||||
setNoAbort();
|
||||
const payload = {
|
||||
text: "Exec approval is unavailable.",
|
||||
channelData: {
|
||||
execApprovalUnavailable: { reason: "no-approval-route" },
|
||||
},
|
||||
} satisfies ReplyPayload;
|
||||
const dispatcher = createDispatcher();
|
||||
const ctx = buildTestCtx({ Provider: "telegram", ChatType: "direct" });
|
||||
const replyResolver = async (
|
||||
_ctx: MsgContext,
|
||||
opts?: GetReplyOptions,
|
||||
_cfg?: OpenClawConfig,
|
||||
) => {
|
||||
await requireToolResultHandler(opts?.onToolResult)(payload);
|
||||
return undefined;
|
||||
};
|
||||
|
||||
await dispatchReplyFromConfig({ ctx, cfg: emptyConfig, dispatcher, replyResolver });
|
||||
|
||||
expect(dispatcher.sendToolResult).toHaveBeenCalledWith(payload);
|
||||
expect(dispatcher.sendFinalReply).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("drops ask_user prompts that terminalize before dispatcher delivery", async () => {
|
||||
setNoAbort();
|
||||
askUserMocks.isAskUserPromptPending.mockResolvedValue(false);
|
||||
|
||||
@@ -329,6 +329,15 @@ describe("executeFollowupTurn", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "unavailable exec approvals",
|
||||
payload: {
|
||||
text: "Exec approval is unavailable.",
|
||||
channelData: {
|
||||
execApprovalUnavailable: { reason: "no-approval-route" },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "ask-user prompts",
|
||||
payload: {
|
||||
|
||||
@@ -688,18 +688,23 @@ describe("exec approval reply helpers", () => {
|
||||
}),
|
||||
).toEqual({
|
||||
text: "Careful.\n\nApproval required. I sent approval DMs to the approvers for this account.",
|
||||
channelData: {
|
||||
execApprovalUnavailable: {
|
||||
reason: "no-approval-route",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it.each(unavailableReasonCases)(
|
||||
"builds unavailable payload for reason $reason",
|
||||
({ reason, channelLabel, expected }) => {
|
||||
expect(
|
||||
buildExecApprovalUnavailableReplyPayload({
|
||||
reason,
|
||||
channelLabel,
|
||||
}).text,
|
||||
).toContain(expected);
|
||||
const payload = buildExecApprovalUnavailableReplyPayload({
|
||||
reason,
|
||||
channelLabel,
|
||||
});
|
||||
expect(payload.text).toContain(expected);
|
||||
expect(payload.channelData).toEqual({ execApprovalUnavailable: { reason } });
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -475,6 +475,11 @@ export function buildExecApprovalUnavailableReplyPayload(
|
||||
params: ExecApprovalUnavailableReplyParams,
|
||||
): ReplyPayload {
|
||||
const lines: string[] = [];
|
||||
const channelData = {
|
||||
execApprovalUnavailable: {
|
||||
reason: params.reason,
|
||||
},
|
||||
};
|
||||
const warningText = params.warningText?.trim();
|
||||
if (warningText) {
|
||||
lines.push(warningText);
|
||||
@@ -484,6 +489,7 @@ export function buildExecApprovalUnavailableReplyPayload(
|
||||
lines.push(getExecApprovalApproverDmNoticeText());
|
||||
return {
|
||||
text: lines.join("\n\n"),
|
||||
channelData,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -535,5 +541,6 @@ export function buildExecApprovalUnavailableReplyPayload(
|
||||
|
||||
return {
|
||||
text: lines.join("\n\n"),
|
||||
channelData,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user