fix(regression): align mattermost send helper runtime usage

This commit is contained in:
Tak Hoffman
2026-03-27 21:44:41 -05:00
parent b171e42117
commit 912a26e759
2 changed files with 60 additions and 8 deletions

View File

@@ -15,6 +15,7 @@ type SendMessageMattermostOptions = NonNullable<
const mockState = vi.hoisted(() => ({
loadConfig: vi.fn(() => ({})),
loadOutboundMediaFromUrl: vi.fn(),
recordActivity: vi.fn(),
resolveMattermostAccount: vi.fn(() => ({
accountId: "default",
botToken: "bot-token",
@@ -38,6 +39,14 @@ vi.mock("../../runtime-api.js", () => ({
loadOutboundMediaFromUrl: mockState.loadOutboundMediaFromUrl,
}));
vi.mock("openclaw/plugin-sdk/config-runtime", () => ({
resolveMarkdownTableMode: vi.fn(() => "off"),
}));
vi.mock("openclaw/plugin-sdk/text-runtime", () => ({
convertMarkdownTables: vi.fn((text: string) => text),
}));
vi.mock("./accounts.js", () => ({
resolveMattermostAccount: mockState.resolveMattermostAccount,
}));
@@ -71,7 +80,7 @@ vi.mock("../runtime.js", () => ({
convertMarkdownTables: (text: string) => text,
},
activity: {
record: vi.fn(),
record: mockState.recordActivity,
},
},
}),
@@ -82,6 +91,7 @@ describe("sendMessageMattermost", () => {
vi.resetModules();
mockState.loadConfig.mockReset();
mockState.loadConfig.mockReturnValue({});
mockState.recordActivity.mockReset();
mockState.resolveMattermostAccount.mockReset();
mockState.resolveMattermostAccount.mockReturnValue({
accountId: "default",
@@ -170,6 +180,36 @@ describe("sendMessageMattermost", () => {
});
});
it("sends with provided cfg even when the runtime store is not initialized", async () => {
const providedCfg = {
channels: {
mattermost: {
botToken: "provided-token",
},
},
};
mockState.resolveMattermostAccount.mockReturnValue({
accountId: "work",
botToken: "provided-token",
baseUrl: "https://mattermost.example.com",
config: {},
});
mockState.recordActivity.mockImplementation(() => {
throw new Error("Mattermost runtime not initialized");
});
await expect(
sendMessageMattermost("channel:town-square", "hello", {
cfg: providedCfg,
accountId: "work",
}),
).resolves.toEqual({
messageId: "post-1",
channelId: "town-square",
});
expect(mockState.loadConfig).not.toHaveBeenCalled();
});
it("loads outbound media with trusted local roots before upload", async () => {
mockState.loadOutboundMediaFromUrl.mockResolvedValueOnce({
buffer: Buffer.from("media-bytes"),

View File

@@ -1,3 +1,5 @@
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime";
import { loadOutboundMediaFromUrl, type OpenClawConfig } from "../runtime-api.js";
import { getMattermostRuntime } from "../runtime.js";
import { resolveMattermostAccount } from "./accounts.js";
@@ -58,6 +60,20 @@ const dmChannelCache = new Map<string, string>();
const getCore = () => getMattermostRuntime();
function recordMattermostOutboundActivity(accountId: string): void {
try {
getCore().channel.activity.record({
channel: "mattermost",
accountId,
direction: "outbound",
});
} catch (error) {
if (!(error instanceof Error) || error.message !== "Mattermost runtime not initialized") {
throw error;
}
}
}
function cacheKey(baseUrl: string, token: string): string {
return `${baseUrl}::${token}`;
}
@@ -421,12 +437,12 @@ export async function sendMessageMattermost(
}
if (message) {
const tableMode = core.channel.text.resolveMarkdownTableMode({
const tableMode = resolveMarkdownTableMode({
cfg,
channel: "mattermost",
accountId,
});
message = core.channel.text.convertMarkdownTables(message, tableMode);
message = convertMarkdownTables(message, tableMode);
}
if (!message && (!fileIds || fileIds.length === 0)) {
@@ -444,11 +460,7 @@ export async function sendMessageMattermost(
props,
});
core.channel.activity.record({
channel: "mattermost",
accountId,
direction: "outbound",
});
recordMattermostOutboundActivity(accountId);
return {
messageId: post.id ?? "unknown",