mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 01:51:24 +00:00
fix: stop hardcoded channel fallback and auto-pick sole configured channel (#23357) (thanks @lbo728)
Co-authored-by: lbo728 <extreme0728@gmail.com>
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { DEFAULT_CHAT_CHANNEL } from "../../channels/registry.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
|
||||
vi.mock("../../config/sessions.js", () => ({
|
||||
@@ -223,16 +222,30 @@ describe("resolveDeliveryTarget", () => {
|
||||
expect(result.threadId).toBe("thread-2");
|
||||
});
|
||||
|
||||
it("falls back to default channel when selection probe fails", async () => {
|
||||
it("uses single configured channel when neither explicit nor session channel exists", async () => {
|
||||
setMainSessionEntry(undefined);
|
||||
vi.mocked(resolveMessageChannelSelection).mockRejectedValueOnce(new Error("no selection"));
|
||||
|
||||
const result = await resolveForAgent({
|
||||
cfg: makeCfg({ bindings: [] }),
|
||||
target: { channel: "last", to: undefined },
|
||||
});
|
||||
expect(result.channel).toBe(DEFAULT_CHAT_CHANNEL);
|
||||
expect(result.channel).toBe("telegram");
|
||||
expect(result.error).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns an error when channel selection is ambiguous", async () => {
|
||||
setMainSessionEntry(undefined);
|
||||
vi.mocked(resolveMessageChannelSelection).mockRejectedValueOnce(
|
||||
new Error("Channel is required when multiple channels are configured: telegram, slack"),
|
||||
);
|
||||
|
||||
const result = await resolveForAgent({
|
||||
cfg: makeCfg({ bindings: [] }),
|
||||
target: { channel: "last", to: undefined },
|
||||
});
|
||||
expect(result.channel).toBeUndefined();
|
||||
expect(result.to).toBeUndefined();
|
||||
expect(result.error?.message).toContain("Channel is required");
|
||||
});
|
||||
|
||||
it("uses sessionKey thread entry before main session entry", async () => {
|
||||
@@ -261,11 +274,12 @@ describe("resolveDeliveryTarget", () => {
|
||||
expect(result.to).toBe("thread-chat");
|
||||
});
|
||||
|
||||
it("uses channel selection result when no previous session target exists", async () => {
|
||||
setMainSessionEntry(undefined);
|
||||
vi.mocked(resolveMessageChannelSelection).mockResolvedValueOnce({
|
||||
channel: "telegram",
|
||||
configured: ["telegram"],
|
||||
it("uses main session channel when channel=last and session route exists", async () => {
|
||||
setMainSessionEntry({
|
||||
sessionId: "sess-4",
|
||||
updatedAt: 1000,
|
||||
lastChannel: "telegram",
|
||||
lastTo: "987654",
|
||||
});
|
||||
|
||||
const result = await resolveForAgent({
|
||||
@@ -274,7 +288,7 @@ describe("resolveDeliveryTarget", () => {
|
||||
});
|
||||
|
||||
expect(result.channel).toBe("telegram");
|
||||
expect(result.to).toBeUndefined();
|
||||
expect(result.mode).toBe("implicit");
|
||||
expect(result.to).toBe("987654");
|
||||
expect(result.error).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { ChannelId } from "../../channels/plugins/types.js";
|
||||
import { DEFAULT_CHAT_CHANNEL } from "../../channels/registry.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import {
|
||||
loadSessionStore,
|
||||
@@ -27,7 +26,7 @@ export async function resolveDeliveryTarget(
|
||||
sessionKey?: string;
|
||||
},
|
||||
): Promise<{
|
||||
channel: Exclude<OutboundChannel, "none">;
|
||||
channel?: Exclude<OutboundChannel, "none">;
|
||||
to?: string;
|
||||
accountId?: string;
|
||||
threadId?: string | number;
|
||||
@@ -57,12 +56,20 @@ export async function resolveDeliveryTarget(
|
||||
});
|
||||
|
||||
let fallbackChannel: Exclude<OutboundChannel, "none"> | undefined;
|
||||
let channelResolutionError: Error | undefined;
|
||||
if (!preliminary.channel) {
|
||||
try {
|
||||
const selection = await resolveMessageChannelSelection({ cfg });
|
||||
fallbackChannel = selection.channel;
|
||||
} catch {
|
||||
fallbackChannel = preliminary.lastChannel ?? DEFAULT_CHAT_CHANNEL;
|
||||
if (preliminary.lastChannel) {
|
||||
fallbackChannel = preliminary.lastChannel;
|
||||
} else {
|
||||
try {
|
||||
const selection = await resolveMessageChannelSelection({ cfg });
|
||||
fallbackChannel = selection.channel;
|
||||
} catch (err) {
|
||||
const detail = err instanceof Error ? err.message : String(err);
|
||||
channelResolutionError = new Error(
|
||||
`${detail} Set delivery.channel explicitly or use a main session with a previous channel.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +84,7 @@ export async function resolveDeliveryTarget(
|
||||
})
|
||||
: preliminary;
|
||||
|
||||
const channel = resolved.channel ?? fallbackChannel ?? DEFAULT_CHAT_CHANNEL;
|
||||
const channel = resolved.channel ?? fallbackChannel;
|
||||
const mode = resolved.mode as "explicit" | "implicit";
|
||||
let toCandidate = resolved.to;
|
||||
|
||||
@@ -105,6 +112,17 @@ export async function resolveDeliveryTarget(
|
||||
? resolved.threadId
|
||||
: undefined;
|
||||
|
||||
if (!channel) {
|
||||
return {
|
||||
channel: undefined,
|
||||
to: undefined,
|
||||
accountId,
|
||||
threadId,
|
||||
mode,
|
||||
error: channelResolutionError,
|
||||
};
|
||||
}
|
||||
|
||||
if (!toCandidate) {
|
||||
return {
|
||||
channel,
|
||||
@@ -112,6 +130,7 @@ export async function resolveDeliveryTarget(
|
||||
accountId,
|
||||
threadId,
|
||||
mode,
|
||||
error: channelResolutionError,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -150,6 +169,6 @@ export async function resolveDeliveryTarget(
|
||||
accountId,
|
||||
threadId,
|
||||
mode,
|
||||
error: docked.ok ? undefined : docked.error,
|
||||
error: docked.ok ? channelResolutionError : docked.error,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,9 +75,9 @@ import {
|
||||
|
||||
function matchesMessagingToolDeliveryTarget(
|
||||
target: MessagingToolSend,
|
||||
delivery: { channel: string; to?: string; accountId?: string },
|
||||
delivery: { channel?: string; to?: string; accountId?: string },
|
||||
): boolean {
|
||||
if (!delivery.to || !target.to) {
|
||||
if (!delivery.channel || !delivery.to || !target.to) {
|
||||
return false;
|
||||
}
|
||||
const channel = delivery.channel.trim().toLowerCase();
|
||||
@@ -611,6 +611,20 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
logWarn(`[cron:${params.job.id}] ${resolvedDelivery.error.message}`);
|
||||
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
|
||||
}
|
||||
if (!resolvedDelivery.channel) {
|
||||
const message = "cron delivery channel is missing";
|
||||
if (!deliveryBestEffort) {
|
||||
return withRunSession({
|
||||
status: "error",
|
||||
error: message,
|
||||
summary,
|
||||
outputText,
|
||||
...telemetry,
|
||||
});
|
||||
}
|
||||
logWarn(`[cron:${params.job.id}] ${message}`);
|
||||
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
|
||||
}
|
||||
if (!resolvedDelivery.to) {
|
||||
const message = "cron delivery target is missing";
|
||||
if (!deliveryBestEffort) {
|
||||
|
||||
Reference in New Issue
Block a user