import { ADAPTER_AGNOSTIC_KEYS, type Agent } from "@paperclipai/shared"; export interface AgentConfigOverlay { runner?: import("@paperclipai/shared").AgentRunnerChoice; identity: Record; adapterType?: string; adapterConfig: Record; heartbeat: Record; debug: Record; runtime: Record; } export function omitUndefinedEntries(value: Record) { return Object.fromEntries( Object.entries(value).filter(([, entryValue]) => entryValue !== undefined), ); } export function buildAgentUpdatePatch(agent: Agent, overlay: AgentConfigOverlay) { const patch: Record = {}; if (overlay.runner !== undefined) patch.runner = overlay.runner; if (Object.keys(overlay.identity).length > 0) { Object.assign(patch, overlay.identity); } if (overlay.adapterType !== undefined) { patch.adapterType = overlay.adapterType; } if (overlay.adapterType !== undefined || Object.keys(overlay.adapterConfig).length > 0) { const existing = (agent.adapterConfig ?? {}) as Record; const nextAdapterConfig = overlay.adapterType !== undefined ? { ...Object.fromEntries( ADAPTER_AGNOSTIC_KEYS .filter((key) => existing[key] !== undefined) .map((key) => [key, existing[key]]), ), ...overlay.adapterConfig, } : { ...existing, ...overlay.adapterConfig, }; patch.adapterConfig = omitUndefinedEntries(nextAdapterConfig); patch.replaceAdapterConfig = true; } if ( Object.keys(overlay.heartbeat).length > 0 || Object.keys(overlay.debug).length > 0 ) { const existingRc = (agent.runtimeConfig ?? {}) as Record; const nextRuntimeConfig: Record = (patch.runtimeConfig as Record | undefined) ?? { ...existingRc }; if (Object.keys(overlay.heartbeat).length > 0) { const existingHb = (existingRc.heartbeat ?? {}) as Record; nextRuntimeConfig.heartbeat = { ...existingHb, ...overlay.heartbeat }; } if (Object.keys(overlay.debug).length > 0) { const existingDebug = (existingRc.debug ?? {}) as Record; const nextDebug = omitUndefinedEntries({ ...existingDebug, ...overlay.debug }); if (Object.keys(nextDebug).length === 0) { delete nextRuntimeConfig.debug; } else { nextRuntimeConfig.debug = nextDebug; } } patch.runtimeConfig = nextRuntimeConfig; } if (Object.keys(overlay.runtime).length > 0) { Object.assign(patch, overlay.runtime); } return patch; }