Merged via squash. Prepared head SHA: 1714ffe6fc1e3ed6a8a120d01d074f1be83c62d3 Co-authored-by: xiwan <931632+xiwan@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
213 lines
7.0 KiB
TypeScript
213 lines
7.0 KiB
TypeScript
import type { LegacyConfigRule } from "./legacy.shared.js";
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
}
|
|
|
|
function hasLegacyThreadBindingTtl(value: unknown): boolean {
|
|
return isRecord(value) && Object.prototype.hasOwnProperty.call(value, "ttlHours");
|
|
}
|
|
|
|
function hasLegacyThreadBindingTtlInAccounts(value: unknown): boolean {
|
|
if (!isRecord(value)) {
|
|
return false;
|
|
}
|
|
return Object.values(value).some((entry) =>
|
|
hasLegacyThreadBindingTtl(isRecord(entry) ? entry.threadBindings : undefined),
|
|
);
|
|
}
|
|
|
|
function isLegacyGatewayBindHostAlias(value: unknown): boolean {
|
|
if (typeof value !== "string") {
|
|
return false;
|
|
}
|
|
const normalized = value.trim().toLowerCase();
|
|
if (!normalized) {
|
|
return false;
|
|
}
|
|
if (
|
|
normalized === "auto" ||
|
|
normalized === "loopback" ||
|
|
normalized === "lan" ||
|
|
normalized === "tailnet" ||
|
|
normalized === "custom"
|
|
) {
|
|
return false;
|
|
}
|
|
return (
|
|
normalized === "0.0.0.0" ||
|
|
normalized === "::" ||
|
|
normalized === "[::]" ||
|
|
normalized === "*" ||
|
|
normalized === "127.0.0.1" ||
|
|
normalized === "localhost" ||
|
|
normalized === "::1" ||
|
|
normalized === "[::1]"
|
|
);
|
|
}
|
|
|
|
export const LEGACY_CONFIG_RULES: LegacyConfigRule[] = [
|
|
{
|
|
path: ["whatsapp"],
|
|
message: "whatsapp config moved to channels.whatsapp (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["telegram"],
|
|
message: "telegram config moved to channels.telegram (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["discord"],
|
|
message: "discord config moved to channels.discord (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["slack"],
|
|
message: "slack config moved to channels.slack (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["signal"],
|
|
message: "signal config moved to channels.signal (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["imessage"],
|
|
message: "imessage config moved to channels.imessage (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["msteams"],
|
|
message: "msteams config moved to channels.msteams (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["session", "threadBindings"],
|
|
message:
|
|
"session.threadBindings.ttlHours was renamed to session.threadBindings.idleHours (auto-migrated on load).",
|
|
match: (value) => hasLegacyThreadBindingTtl(value),
|
|
},
|
|
{
|
|
path: ["channels", "discord", "threadBindings"],
|
|
message:
|
|
"channels.discord.threadBindings.ttlHours was renamed to channels.discord.threadBindings.idleHours (auto-migrated on load).",
|
|
match: (value) => hasLegacyThreadBindingTtl(value),
|
|
},
|
|
{
|
|
path: ["channels", "discord", "accounts"],
|
|
message:
|
|
"channels.discord.accounts.<id>.threadBindings.ttlHours was renamed to channels.discord.accounts.<id>.threadBindings.idleHours (auto-migrated on load).",
|
|
match: (value) => hasLegacyThreadBindingTtlInAccounts(value),
|
|
},
|
|
{
|
|
path: ["routing", "allowFrom"],
|
|
message:
|
|
"routing.allowFrom was removed; use channels.whatsapp.allowFrom instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["routing", "bindings"],
|
|
message: "routing.bindings was moved; use top-level bindings instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["routing", "agents"],
|
|
message: "routing.agents was moved; use agents.list instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["routing", "defaultAgentId"],
|
|
message:
|
|
"routing.defaultAgentId was moved; use agents.list[].default instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["routing", "agentToAgent"],
|
|
message:
|
|
"routing.agentToAgent was moved; use tools.agentToAgent instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["routing", "groupChat", "requireMention"],
|
|
message:
|
|
'routing.groupChat.requireMention was removed; use channels.whatsapp/telegram/imessage groups defaults (e.g. channels.whatsapp.groups."*".requireMention) instead (auto-migrated on load).',
|
|
},
|
|
{
|
|
path: ["routing", "groupChat", "mentionPatterns"],
|
|
message:
|
|
"routing.groupChat.mentionPatterns was moved; use agents.list[].groupChat.mentionPatterns or messages.groupChat.mentionPatterns instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["routing", "queue"],
|
|
message: "routing.queue was moved; use messages.queue instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["routing", "transcribeAudio"],
|
|
message:
|
|
"routing.transcribeAudio was moved; use tools.media.audio.models instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["telegram", "requireMention"],
|
|
message:
|
|
'telegram.requireMention was removed; use channels.telegram.groups."*".requireMention instead (auto-migrated on load).',
|
|
},
|
|
{
|
|
path: ["identity"],
|
|
message: "identity was moved; use agents.list[].identity instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["agent"],
|
|
message:
|
|
"agent.* was moved; use agents.defaults (and tools.* for tool/elevated/exec settings) instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["memorySearch"],
|
|
message:
|
|
"top-level memorySearch was moved; use agents.defaults.memorySearch instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["tools", "bash"],
|
|
message: "tools.bash was removed; use tools.exec instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["agent", "model"],
|
|
message:
|
|
"agent.model string was replaced by agents.defaults.model.primary/fallbacks and agents.defaults.models (auto-migrated on load).",
|
|
match: (value) => typeof value === "string",
|
|
},
|
|
{
|
|
path: ["agent", "imageModel"],
|
|
message:
|
|
"agent.imageModel string was replaced by agents.defaults.imageModel.primary/fallbacks (auto-migrated on load).",
|
|
match: (value) => typeof value === "string",
|
|
},
|
|
{
|
|
path: ["agent", "allowedModels"],
|
|
message: "agent.allowedModels was replaced by agents.defaults.models (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["agent", "modelAliases"],
|
|
message:
|
|
"agent.modelAliases was replaced by agents.defaults.models.*.alias (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["agent", "modelFallbacks"],
|
|
message:
|
|
"agent.modelFallbacks was replaced by agents.defaults.model.fallbacks (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["agent", "imageModelFallbacks"],
|
|
message:
|
|
"agent.imageModelFallbacks was replaced by agents.defaults.imageModel.fallbacks (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["messages", "tts", "enabled"],
|
|
message: "messages.tts.enabled was replaced by messages.tts.auto (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["gateway", "token"],
|
|
message: "gateway.token is ignored; use gateway.auth.token instead (auto-migrated on load).",
|
|
},
|
|
{
|
|
path: ["gateway", "bind"],
|
|
message:
|
|
"gateway.bind host aliases (for example 0.0.0.0/localhost) are legacy; use bind modes (lan/loopback/custom/tailnet/auto) instead (auto-migrated on load).",
|
|
match: (value) => isLegacyGatewayBindHostAlias(value),
|
|
requireSourceLiteral: true,
|
|
},
|
|
{
|
|
path: ["heartbeat"],
|
|
message:
|
|
"top-level heartbeat is not a valid config path; use agents.defaults.heartbeat (cadence/target/model settings) or channels.defaults.heartbeat (showOk/showAlerts/useIndicator).",
|
|
},
|
|
];
|