openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
86 lines (85 loc) • 5 kB
JavaScript
import { r as asNullableRecord } from "./record-coerce-DItp3I4t.js";
import { l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import "./session-key-BnWWjqNc.js";
import { n as normalizeAccountId, r as normalizeOptionalAccountId } from "./account-id-CETVCrTz.js";
import { i as normalizeChatChannelId } from "./ids-BVZRYG0I.js";
import { i as listRouteBindings } from "./bindings-CI-O7TMQ.js";
import { n as formatSetExplicitDefaultInstruction, r as formatSetExplicitDefaultToConfiguredInstruction, t as formatChannelAccountsDefaultPath } from "./default-account-warnings-CK3UKJwX.js";
//#region src/commands/doctor/shared/default-account-warnings.ts
function normalizeBindingChannelKey(raw) {
const normalized = normalizeChatChannelId(raw);
if (normalized) return normalized;
return normalizeLowercaseStringOrEmpty(raw);
}
function collectChannelsMissingDefaultAccount(cfg) {
const channels = asNullableRecord(cfg.channels);
if (!channels) return [];
const contexts = [];
for (const [channelKey, rawChannel] of Object.entries(channels)) {
const channel = asNullableRecord(rawChannel);
if (!channel) continue;
const accounts = asNullableRecord(channel.accounts);
if (!accounts) continue;
const normalizedAccountIds = Array.from(new Set(Object.keys(accounts).map((accountId) => normalizeAccountId(accountId)).filter(Boolean))).toSorted((a, b) => a.localeCompare(b));
if (normalizedAccountIds.length === 0 || normalizedAccountIds.includes("default")) continue;
contexts.push({
channelKey,
channel,
normalizedAccountIds
});
}
return contexts;
}
/** Warn when account-scoped route bindings do not cover channels without accounts.default. */
function collectMissingDefaultAccountBindingWarnings(cfg) {
const bindings = listRouteBindings(cfg);
const warnings = [];
for (const { channelKey, normalizedAccountIds } of collectChannelsMissingDefaultAccount(cfg)) {
const accountIdSet = new Set(normalizedAccountIds);
const channelPattern = normalizeBindingChannelKey(channelKey);
let hasWildcardBinding = false;
const coveredAccountIds = /* @__PURE__ */ new Set();
for (const binding of bindings) {
const bindingRecord = asNullableRecord(binding);
if (!bindingRecord) continue;
const match = asNullableRecord(bindingRecord.match);
if (!match) continue;
const matchChannel = typeof match.channel === "string" ? normalizeBindingChannelKey(match.channel) : "";
if (!matchChannel || matchChannel !== channelPattern) continue;
const rawAccountId = normalizeOptionalString(match.accountId) ?? "";
if (!rawAccountId) continue;
if (rawAccountId === "*") {
hasWildcardBinding = true;
continue;
}
const normalizedBindingAccountId = normalizeAccountId(rawAccountId);
if (accountIdSet.has(normalizedBindingAccountId)) coveredAccountIds.add(normalizedBindingAccountId);
}
if (hasWildcardBinding) continue;
const uncoveredAccountIds = normalizedAccountIds.filter((accountId) => !coveredAccountIds.has(accountId));
if (uncoveredAccountIds.length === 0) continue;
if (coveredAccountIds.size > 0) {
warnings.push(`- channels.${channelKey}: accounts.default is missing and account bindings only cover a subset of configured accounts. Uncovered accounts: ${uncoveredAccountIds.join(", ")}. Add bindings[].match.accountId for uncovered accounts (or "*"), or add ${formatChannelAccountsDefaultPath(channelKey)}.`);
continue;
}
warnings.push(`- channels.${channelKey}: accounts.default is missing and no valid account-scoped binding exists for configured accounts (${normalizedAccountIds.join(", ")}). Channel-only bindings (no accountId) match only default. Add bindings[].match.accountId for one of these accounts (or "*"), or add ${formatChannelAccountsDefaultPath(channelKey)}.`);
}
return warnings;
}
/** Warn when multi-account channels omit or misconfigure an explicit default account. */
function collectMissingExplicitDefaultAccountWarnings(cfg) {
const warnings = [];
for (const { channelKey, channel, normalizedAccountIds } of collectChannelsMissingDefaultAccount(cfg)) {
if (normalizedAccountIds.length < 2) continue;
const preferredDefault = normalizeOptionalAccountId(typeof channel.defaultAccount === "string" ? channel.defaultAccount : void 0);
if (preferredDefault) {
if (normalizedAccountIds.includes(preferredDefault)) continue;
warnings.push(`- channels.${channelKey}: defaultAccount is set to "${preferredDefault}" but does not match configured accounts (${normalizedAccountIds.join(", ")}). ${formatSetExplicitDefaultToConfiguredInstruction({ channelKey })} to avoid fallback routing.`);
continue;
}
warnings.push(`- channels.${channelKey}: multiple accounts are configured but no explicit default is set. ${formatSetExplicitDefaultInstruction(channelKey)} to avoid fallback routing.`);
}
return warnings;
}
//#endregion
export { collectMissingDefaultAccountBindingWarnings, collectMissingExplicitDefaultAccountWarnings };