mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-17 20:21:13 +00:00
103 lines
3.7 KiB
TypeScript
103 lines
3.7 KiB
TypeScript
import { normalizeChannelId } from "../channels/plugins/index.js";
|
|
import { listChannelPlugins } from "../channels/plugins/registry.js";
|
|
import { getActivePluginChannelRegistryVersion } from "../plugins/runtime.js";
|
|
import { resolveAccountEntry } from "../routing/account-lookup.js";
|
|
import { normalizeAccountId } from "../routing/session-key.js";
|
|
import type { OpenClawConfig } from "./config.js";
|
|
import type { MarkdownTableMode } from "./types.base.js";
|
|
|
|
type MarkdownConfigEntry = {
|
|
markdown?: {
|
|
tables?: MarkdownTableMode;
|
|
};
|
|
};
|
|
|
|
type MarkdownConfigSection = MarkdownConfigEntry & {
|
|
accounts?: Record<string, MarkdownConfigEntry>;
|
|
};
|
|
|
|
function buildDefaultTableModes(): Map<string, MarkdownTableMode> {
|
|
return new Map(
|
|
listChannelPlugins()
|
|
.flatMap((plugin) => {
|
|
const defaultMarkdownTableMode = plugin.messaging?.defaultMarkdownTableMode;
|
|
return defaultMarkdownTableMode ? [[plugin.id, defaultMarkdownTableMode] as const] : [];
|
|
})
|
|
.toSorted(([left], [right]) => left.localeCompare(right)),
|
|
);
|
|
}
|
|
|
|
let cachedDefaultTableModes: Map<string, MarkdownTableMode> | null = null;
|
|
let cachedDefaultTableModesRegistryVersion: number | null = null;
|
|
|
|
function getDefaultTableModes(): Map<string, MarkdownTableMode> {
|
|
const registryVersion = getActivePluginChannelRegistryVersion();
|
|
if (!cachedDefaultTableModes || cachedDefaultTableModesRegistryVersion !== registryVersion) {
|
|
cachedDefaultTableModes = buildDefaultTableModes();
|
|
cachedDefaultTableModesRegistryVersion = registryVersion;
|
|
}
|
|
return cachedDefaultTableModes;
|
|
}
|
|
|
|
const EMPTY_DEFAULT_TABLE_MODES = new Map<string, MarkdownTableMode>();
|
|
|
|
function bindDefaultTableModesMethod<TValue>(value: TValue): TValue {
|
|
if (typeof value !== "function") {
|
|
return value;
|
|
}
|
|
return value.bind(getDefaultTableModes()) as TValue;
|
|
}
|
|
|
|
export const DEFAULT_TABLE_MODES: ReadonlyMap<string, MarkdownTableMode> = new Proxy(
|
|
EMPTY_DEFAULT_TABLE_MODES,
|
|
{
|
|
get(_target, prop, _receiver) {
|
|
return bindDefaultTableModesMethod(Reflect.get(getDefaultTableModes(), prop));
|
|
},
|
|
},
|
|
);
|
|
|
|
const isMarkdownTableMode = (value: unknown): value is MarkdownTableMode =>
|
|
value === "off" || value === "bullets" || value === "code" || value === "block";
|
|
|
|
function resolveMarkdownModeFromSection(
|
|
section: MarkdownConfigSection | undefined,
|
|
accountId?: string | null,
|
|
): MarkdownTableMode | undefined {
|
|
if (!section) {
|
|
return undefined;
|
|
}
|
|
const normalizedAccountId = normalizeAccountId(accountId);
|
|
const accounts = section.accounts;
|
|
if (accounts && typeof accounts === "object") {
|
|
const match = resolveAccountEntry(accounts, normalizedAccountId);
|
|
const matchMode = match?.markdown?.tables;
|
|
if (isMarkdownTableMode(matchMode)) {
|
|
return matchMode;
|
|
}
|
|
}
|
|
const sectionMode = section.markdown?.tables;
|
|
return isMarkdownTableMode(sectionMode) ? sectionMode : undefined;
|
|
}
|
|
|
|
export function resolveMarkdownTableMode(params: {
|
|
cfg?: Partial<OpenClawConfig>;
|
|
channel?: string | null;
|
|
accountId?: string | null;
|
|
}): MarkdownTableMode {
|
|
const channel = normalizeChannelId(params.channel);
|
|
const defaultMode = channel ? (getDefaultTableModes().get(channel) ?? "code") : "code";
|
|
if (!channel || !params.cfg) {
|
|
return defaultMode;
|
|
}
|
|
const channelsConfig = params.cfg.channels as Record<string, unknown> | undefined;
|
|
const section = (channelsConfig?.[channel] ??
|
|
(params.cfg as Record<string, unknown> | undefined)?.[channel]) as
|
|
| MarkdownConfigSection
|
|
| undefined;
|
|
const resolved = resolveMarkdownModeFromSection(section, params.accountId) ?? defaultMode;
|
|
// "block" stays schema-valid for the shared markdown seam, but this PR
|
|
// keeps runtime delivery on safe text rendering until Slack send support lands.
|
|
return resolved === "block" ? "code" : resolved;
|
|
}
|