fix(outbound): unify resolved cfg threading across send paths (#33987)

This commit is contained in:
Josh Avant
2026-03-04 00:20:44 -06:00
committed by GitHub
parent 4d183af0cf
commit 646817dd80
62 changed files with 1780 additions and 117 deletions

View File

@@ -296,16 +296,18 @@ export const ircPlugin: ChannelPlugin<ResolvedIrcAccount, IrcProbe> = {
chunker: (text, limit) => getIrcRuntime().channel.text.chunkMarkdownText(text, limit),
chunkerMode: "markdown",
textChunkLimit: 350,
sendText: async ({ to, text, accountId, replyToId }) => {
sendText: async ({ cfg, to, text, accountId, replyToId }) => {
const result = await sendMessageIrc(to, text, {
cfg: cfg as CoreConfig,
accountId: accountId ?? undefined,
replyTo: replyToId ?? undefined,
});
return { channel: "irc", ...result };
},
sendMedia: async ({ to, text, mediaUrl, accountId, replyToId }) => {
sendMedia: async ({ cfg, to, text, mediaUrl, accountId, replyToId }) => {
const combined = mediaUrl ? `${text}\n\nAttachment: ${mediaUrl}` : text;
const result = await sendMessageIrc(to, combined, {
cfg: cfg as CoreConfig,
accountId: accountId ?? undefined,
replyTo: replyToId ?? undefined,
});

View File

@@ -0,0 +1,116 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { IrcClient } from "./client.js";
import type { CoreConfig } from "./types.js";
const hoisted = vi.hoisted(() => {
const loadConfig = vi.fn();
const resolveMarkdownTableMode = vi.fn(() => "preserve");
const convertMarkdownTables = vi.fn((text: string) => text);
const record = vi.fn();
return {
loadConfig,
resolveMarkdownTableMode,
convertMarkdownTables,
record,
resolveIrcAccount: vi.fn(() => ({
configured: true,
accountId: "default",
host: "irc.example.com",
nick: "openclaw",
port: 6697,
tls: true,
})),
normalizeIrcMessagingTarget: vi.fn((value: string) => value.trim()),
connectIrcClient: vi.fn(),
buildIrcConnectOptions: vi.fn(() => ({})),
};
});
vi.mock("./runtime.js", () => ({
getIrcRuntime: () => ({
config: {
loadConfig: hoisted.loadConfig,
},
channel: {
text: {
resolveMarkdownTableMode: hoisted.resolveMarkdownTableMode,
convertMarkdownTables: hoisted.convertMarkdownTables,
},
activity: {
record: hoisted.record,
},
},
}),
}));
vi.mock("./accounts.js", () => ({
resolveIrcAccount: hoisted.resolveIrcAccount,
}));
vi.mock("./normalize.js", () => ({
normalizeIrcMessagingTarget: hoisted.normalizeIrcMessagingTarget,
}));
vi.mock("./client.js", () => ({
connectIrcClient: hoisted.connectIrcClient,
}));
vi.mock("./connect-options.js", () => ({
buildIrcConnectOptions: hoisted.buildIrcConnectOptions,
}));
vi.mock("./protocol.js", async () => {
const actual = await vi.importActual<typeof import("./protocol.js")>("./protocol.js");
return {
...actual,
makeIrcMessageId: () => "irc-msg-1",
};
});
import { sendMessageIrc } from "./send.js";
describe("sendMessageIrc cfg threading", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("uses explicitly provided cfg without loading runtime config", async () => {
const providedCfg = { source: "provided" } as unknown as CoreConfig;
const client = {
isReady: vi.fn(() => true),
sendPrivmsg: vi.fn(),
} as unknown as IrcClient;
const result = await sendMessageIrc("#room", "hello", {
cfg: providedCfg,
client,
accountId: "work",
});
expect(hoisted.loadConfig).not.toHaveBeenCalled();
expect(hoisted.resolveIrcAccount).toHaveBeenCalledWith({
cfg: providedCfg,
accountId: "work",
});
expect(client.sendPrivmsg).toHaveBeenCalledWith("#room", "hello");
expect(result).toEqual({ messageId: "irc-msg-1", target: "#room" });
});
it("falls back to runtime config when cfg is omitted", async () => {
const runtimeCfg = { source: "runtime" } as unknown as CoreConfig;
hoisted.loadConfig.mockReturnValueOnce(runtimeCfg);
const client = {
isReady: vi.fn(() => true),
sendPrivmsg: vi.fn(),
} as unknown as IrcClient;
await sendMessageIrc("#ops", "ping", { client });
expect(hoisted.loadConfig).toHaveBeenCalledTimes(1);
expect(hoisted.resolveIrcAccount).toHaveBeenCalledWith({
cfg: runtimeCfg,
accountId: undefined,
});
expect(client.sendPrivmsg).toHaveBeenCalledWith("#ops", "ping");
});
});

View File

@@ -8,6 +8,7 @@ import { getIrcRuntime } from "./runtime.js";
import type { CoreConfig } from "./types.js";
type SendIrcOptions = {
cfg?: CoreConfig;
accountId?: string;
replyTo?: string;
target?: string;
@@ -37,7 +38,7 @@ export async function sendMessageIrc(
opts: SendIrcOptions = {},
): Promise<SendIrcResult> {
const runtime = getIrcRuntime();
const cfg = runtime.config.loadConfig() as CoreConfig;
const cfg = (opts.cfg ?? runtime.config.loadConfig()) as CoreConfig;
const account = resolveIrcAccount({
cfg,
accountId: opts.accountId,