fix(delivery): require outbound send result for success

This commit is contained in:
Peter Steinberger
2026-05-07 01:03:11 +01:00
parent b6ae0b83a6
commit 372e270871
3 changed files with 20 additions and 3 deletions

View File

@@ -127,6 +127,7 @@ Docs: https://docs.openclaw.ai
- CLI/completion: guard the shell-profile source line written by `openclaw completion --install` with a file existence check (`[ -f ... ] && source ...` for bash/zsh, `test -f ...; and source ...` for fish) so uninstalling OpenClaw no longer makes new login shells error on a missing completion cache. (#78659) Thanks @sjf.
- Cron/doctor: repair persisted cron jobs whose `payload.model` was stored as `"default"`, `"null"`, blank, or JSON `null` by removing the bad override during `openclaw doctor --fix` while keeping cron runtime model validation strict. Fixes #78549. Thanks @bizzle12368239.
- Telegram: honor `accessGroup:*` sender allowlists for DMs, groups, native commands, and callback authorization before applying Telegram's numeric sender-ID checks. Fixes #78660. Thanks @manugc.
- Agent delivery: report `deliverySucceeded=false` when outbound delivery returns no adapter result, so claimed/empty delivery paths no longer masquerade as successful sends. Fixes #78532. Thanks @joeyfrasier.
- Doctor/OpenAI Codex: revert the 2026.5.5 `doctor --fix` repair that rewrote valid `openai-codex/*` ChatGPT/Codex OAuth routes to `openai/*`, which could break OAuth-only GPT-5.5 setups or accidentally move users onto the OpenAI API-key route. If 2026.5.5 already changed your default model, run `openclaw models set openai-codex/gpt-5.5 && openclaw config validate` to switch the default agent back to the Codex OAuth PI route. Fixes #78407.
- Discord/groups: instruct group-chat agents to stay silent when a message is addressed to someone else, replying only when invited or correcting key facts. (#78615)
- Discord/groups: tell Discord-channel agents to wrap bare URLs as `<https://example.com>` so link previews do not expand into uninvited embeds. (#78614)

View File

@@ -216,7 +216,12 @@ describe("normalizeAgentCommandReplyPayloads", () => {
});
it("reports successful requested delivery", async () => {
deliverOutboundPayloadsMock.mockResolvedValue([]);
deliverOutboundPayloadsMock.mockResolvedValue([
{
channel: "slack",
messageId: "m1",
},
]);
const delivered = await deliverMediaReplyForTest({
key: "agent:tester:slack:direct:alice",
@@ -226,6 +231,17 @@ describe("normalizeAgentCommandReplyPayloads", () => {
expect(delivered.deliverySucceeded).toBe(true);
});
it("does not report success when delivery claims no adapter result", async () => {
deliverOutboundPayloadsMock.mockResolvedValue([]);
const delivered = await deliverMediaReplyForTest({
key: "agent:tester:slack:direct:alice",
agentId: "tester",
} as never);
expect(delivered.deliverySucceeded).toBe(false);
});
it("does not report success when best-effort delivery records an error", async () => {
deliverOutboundPayloadsMock.mockImplementationOnce(async (params: unknown) => {
(params as { onError?: (err: unknown) => void }).onError?.(new Error("send failed"));

View File

@@ -381,7 +381,7 @@ export async function deliverAgentCommandResult(params: {
}
if (deliver && deliveryChannel && !isInternalMessageChannel(deliveryChannel)) {
if (deliveryTarget) {
await deliverOutboundPayloads({
const deliveryResults = await deliverOutboundPayloads({
cfg,
channel: deliveryChannel,
to: deliveryTarget,
@@ -395,7 +395,7 @@ export async function deliverAgentCommandResult(params: {
onPayload: logPayload,
deps: createOutboundSendDeps(deps),
});
deliverySucceeded = !deliveryHadError;
deliverySucceeded = deliveryResults.length > 0 && !deliveryHadError;
}
}