openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
335 lines (334 loc) • 12.5 kB
JavaScript
import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import "./utils-P__uGsPB.js";
import { n as normalizeAgentId } from "./agent-id-CeT3w4ap.js";
import { O as tryResolveSoleAgentId, i as listAgentEntries, s as readAgentRosterProperty } from "./agent-scope-config-DcbEhP0R.js";
import "./session-key-BnWWjqNc.js";
import { n as resolveDefaultAgentWorkspaceDir } from "./workspace-default-DPT1Dhad.js";
import { i as tryGetLegacyDefaultAgentId, r as retainLegacyDefaultAgentId } from "./legacy.default-agent-owner-BGwEdQRe.js";
import { t as isChannelConfigMetadataKey } from "./config-metadata-aX1D2IMg.js";
import { t as normalizeRouteBindingChannelId } from "./binding-scope-ZjLCBNrG.js";
import { t as isPerAgentSessionStoreConfig } from "./session-store-config-C5gZ4u4F.js";
//#region src/config/legacy.default-agent-roles.ts
function isChannelWideBinding(binding, channelId) {
const match = binding.match;
return isRecord(match) && normalizeRouteBindingChannelId(typeof match.channel === "string" ? match.channel : void 0) === channelId && (typeof match.accountId === "string" ? match.accountId.trim() : void 0) === "*" && match.peer === void 0 && !normalizeOptionalString(typeof match.guildId === "string" ? match.guildId : void 0) && !normalizeOptionalString(typeof match.teamId === "string" ? match.teamId : void 0) && (!Array.isArray(match.roles) || match.roles.length === 0);
}
function listUnboundAmbientChannelIds(cfg, ambientChannelIds) {
if (cfg.bindings && !Array.isArray(cfg.bindings)) return [];
const bindings = (cfg.bindings ?? []).filter((binding) => isRecord(binding) && binding.type !== "acp");
const channels = new Set(ambientChannelIds.map(normalizeRouteBindingChannelId).filter((id) => Boolean(id)));
if (isRecord(cfg.channels)) for (const [id, value] of Object.entries(cfg.channels)) {
const channelId = normalizeRouteBindingChannelId(id);
if (channelId && !isChannelConfigMetadataKey(id) && (!isRecord(value) || value.enabled !== false)) channels.add(channelId);
}
return [...channels].toSorted().filter((channelId) => !bindings.some((binding) => isChannelWideBinding(binding, channelId)));
}
/** Preserve a legacy workspace locator without assigning any runtime ownership. */
function resolveLegacyAgentWorkspacePin(defaultWorkspace, entry, options = {}) {
return !Object.hasOwn(entry, "workspace") || typeof entry.workspace === "string" && entry.workspace.trim().length === 0 ? normalizeOptionalString(defaultWorkspace) ?? resolveDefaultAgentWorkspaceDir(options.env, options.homedir) : void 0;
}
function resolveLegacyFirstAgentWorkspacePin(agents, entries, options = {}) {
return agents.ownership === void 0 && entries.length > 1 && entries.every((entry) => !Object.hasOwn(entry, "default") || entry.default === false) ? resolveLegacyAgentWorkspacePin(isRecord(agents.defaults) ? agents.defaults.workspace : void 0, entries[0], options) : void 0;
}
function materializeLegacyDefaultAgentRoles(cfg, legacyDefaultAgentId, options = {}) {
const agentId = normalizeAgentId(legacyDefaultAgentId);
let next = cfg;
const insertedPaths = [];
if (options.materializeWorkspace) {
const entries = { ...next.agents?.entries };
const entryKey = Object.keys(entries).find((candidate) => normalizeAgentId(candidate) === agentId);
const entry = entryKey ? entries[entryKey] : void 0;
const workspace = entry ? resolveLegacyAgentWorkspacePin(next.agents?.defaults?.workspace, entry, options) : void 0;
if (entryKey && entry && workspace !== void 0) {
entries[entryKey] = {
...entry,
workspace
};
next = {
...next,
agents: {
...next.agents,
entries
}
};
insertedPaths.push([
"agents",
"entries",
entryKey,
"workspace"
]);
}
}
const channels = listUnboundAmbientChannelIds(cfg, options.ambientChannelIds ?? []);
if (channels.length > 0) {
next = {
...next,
bindings: [...Array.isArray(next.bindings) ? next.bindings : [], ...channels.map((channel) => ({
agentId,
match: {
channel,
accountId: "*"
}
}))]
};
insertedPaths.push(["bindings"]);
}
const rawDefaults = cfg.agents?.defaults;
const defaults = isRecord(rawDefaults) ? rawDefaults : void 0;
if (rawDefaults === void 0 || defaults) {
const soleFallback = normalizeAgentId(tryResolveSoleAgentId(cfg) ?? "main");
const unset = (key) => defaults?.[key] === void 0 || isRecord(defaults[key]) && !Object.hasOwn(defaults[key], "agentId");
const materializedDefaults = { ...defaults };
let changed = false;
const materialize = (key, enabled) => {
if (!enabled) return;
materializedDefaults[key] = {
...isRecord(materializedDefaults[key]) ? materializedDefaults[key] : {},
agentId
};
insertedPaths.push([
"agents",
"defaults",
key,
"agentId"
]);
changed = true;
};
materialize("heartbeat", !listAgentEntries(cfg).some((entry) => entry.heartbeat) && defaults?.heartbeat === void 0);
materialize("systemAgent", unset("systemAgent"));
materialize("authInheritance", agentId !== soleFallback && unset("authInheritance"));
materialize("sessionStore", options.materializeSessionStore !== false && !isPerAgentSessionStoreConfig(cfg.session?.store) && unset("sessionStore"));
if (changed) next = {
...next,
agents: {
...next.agents,
defaults: materializedDefaults
}
};
}
const talk = isRecord(cfg.talk) ? cfg.talk : void 0;
if ((cfg.talk === void 0 || talk) && (!talk || !Object.hasOwn(talk, "agentId"))) {
next = {
...next,
talk: {
...talk,
agentId
}
};
insertedPaths.push(["talk", "agentId"]);
}
return {
config: next,
insertedPaths
};
}
//#endregion
//#region src/config/legacy.roster.ts
/** Keeps Doctor's allocated identities tied to their original authored list positions. */
function projectLegacyAgentRosterEntries(list) {
const entries = [];
const diagnostics = [];
const ids = /* @__PURE__ */ new Set();
for (const [sourceIndex, value] of list.entries()) {
if (!isRecord(value)) {
diagnostics.push(`Removed malformed agents.list[${sourceIndex}] entry.`);
continue;
}
const rawId = typeof value.id === "string" && value.id.trim() ? value.id.trim() : "agent";
const requestedId = normalizeAgentId(rawId);
if (requestedId !== rawId) diagnostics.push(`Normalized agents.list id "${rawId}" → agents.entries.${requestedId}.`);
let id = requestedId;
let suffix = 2;
while (ids.has(id)) {
id = `${requestedId}-${suffix}`;
suffix += 1;
}
const { id: _id, ...config } = value;
entries.push({
sourceIndex,
id,
config
});
ids.add(id);
if (id !== requestedId) diagnostics.push(`Moved duplicate agents.list id "${requestedId}" to agents.entries.${id}.`);
}
return {
entries,
diagnostics
};
}
/** Converts a valid legacy roster without applying ownership or runtime migrations. */
function parseLegacyAgentRoster(value) {
if (!Array.isArray(value)) return;
const ids = /* @__PURE__ */ new Set();
const entries = [];
for (const entry of value) {
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return;
const { id, ...config } = entry;
if (typeof id !== "string" || id.trim() !== id || !id) return;
const normalizedId = normalizeAgentId(id);
if (normalizedId !== id || ids.has(normalizedId)) return;
ids.add(id);
entries.push([id, config]);
}
return {
entries: Object.fromEntries(entries),
order: [...ids]
};
}
function migratePersistedImplicitMainRoster(raw, options = {}) {
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {
config: raw,
changed: false,
diagnostics: []
};
const root = raw;
if (Object.hasOwn(root, "agents") && (!root.agents || typeof root.agents !== "object" || Array.isArray(root.agents))) return {
config: raw,
changed: false,
diagnostics: []
};
let agents = root.agents && typeof root.agents === "object" && !Array.isArray(root.agents) ? root.agents : {};
let convertedLegacyList = false;
let legacyRoster;
let rosterProperty = readAgentRosterProperty({
...root,
agents
});
if (rosterProperty?.kind === "list") {
const roster = parseLegacyAgentRoster(rosterProperty.value);
if (!roster) return {
config: raw,
changed: false,
diagnostics: []
};
legacyRoster = roster;
const { list: _list, ...rest } = agents;
agents = {
...rest,
entries: roster.entries
};
convertedLegacyList = true;
rosterProperty = readAgentRosterProperty({
...root,
agents
});
}
const entries = rosterProperty?.kind === "entries" ? rosterProperty.value : void 0;
if (!rosterProperty || entries && typeof entries === "object" && !Array.isArray(entries) && Object.keys(entries).length === 0) {
if (agents.ownership === "explicit") return {
config: convertedLegacyList ? {
...root,
agents
} : raw,
changed: convertedLegacyList,
diagnostics: convertedLegacyList ? ["Moved agents.list to keyed agents.entries."] : []
};
return {
config: {
...root,
agents: {
...agents,
entries: { main: {} }
}
},
changed: true,
diagnostics: convertedLegacyList ? ["Moved agents.list to keyed agents.entries."] : []
};
}
if (!entries || typeof entries !== "object" || Array.isArray(entries)) return {
config: raw,
changed: false,
diagnostics: []
};
const roster = entries;
const validIds = legacyRoster?.order ?? Object.entries(roster).flatMap(([id, entry]) => entry && typeof entry === "object" && !Array.isArray(entry) ? [id] : []);
if (validIds.length === 0) return {
config: raw,
changed: false,
diagnostics: []
};
if (validIds.some((id) => {
const entry = roster[id];
return Object.hasOwn(entry, "default") && typeof entry.default !== "boolean";
})) return {
config: raw,
changed: false,
diagnostics: []
};
const markedIds = validIds.filter((id) => roster[id].default === true);
const hasValidLegacyMarker = agents.ownership !== "explicit" && markedIds.length === 1;
const legacyDefaultAgentId = tryGetLegacyDefaultAgentId(raw) ?? (validIds.length > 1 && hasValidLegacyMarker ? markedIds[0] : void 0);
let nextRoot = {
...root,
agents
};
let insertedPaths = [];
const diagnostics = convertedLegacyList ? ["Moved agents.list to keyed agents.entries."] : [];
let changed = convertedLegacyList;
if (legacyRoster && !legacyDefaultAgentId) {
const firstId = legacyRoster.order[0];
const entry = legacyRoster.entries[firstId];
const workspace = resolveLegacyFirstAgentWorkspacePin(agents, legacyRoster.order.map((id) => legacyRoster.entries[id]), options);
if (workspace !== void 0) {
nextRoot = {
...nextRoot,
agents: {
...agents,
entries: {
...roster,
[firstId]: {
...entry,
workspace
}
}
}
};
insertedPaths.push([
"agents",
"entries",
firstId,
"workspace"
]);
diagnostics.push("Preserved the first legacy agent's existing workspace.");
}
}
if (legacyDefaultAgentId && options.materializeRoles !== false) {
const materialized = materializeLegacyDefaultAgentRoles(nextRoot, legacyDefaultAgentId, options);
nextRoot = materialized.config;
insertedPaths = materialized.insertedPaths;
if (insertedPaths.length > 0) {
diagnostics.push("Materialized legacy per-surface agent ownership.");
changed = true;
}
}
if (hasValidLegacyMarker) {
const nextAgents = nextRoot.agents ?? agents;
const materializedEntries = nextAgents.entries ?? roster;
nextRoot = {
...nextRoot,
agents: {
...nextAgents,
entries: Object.fromEntries(Object.entries(materializedEntries).map(([id, entry]) => {
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [id, entry];
const { default: _default, ...rest } = entry;
return [id, rest];
}))
}
};
diagnostics.push("Removed retired agents.entries.*.default markers.");
changed = true;
}
const config = changed ? nextRoot : raw;
retainLegacyDefaultAgentId(config, legacyDefaultAgentId);
return {
config,
changed,
diagnostics,
...insertedPaths.length > 0 ? { insertedPaths } : {},
...legacyDefaultAgentId ? { retainedLegacyDefaultAgentId: legacyDefaultAgentId } : {}
};
}
//#endregion
export { resolveLegacyFirstAgentWorkspacePin as a, materializeLegacyDefaultAgentRoles as i, parseLegacyAgentRoster as n, projectLegacyAgentRosterEntries as r, migratePersistedImplicitMainRoster as t };