import type { Agent } from "@penclipai/shared"; export interface AgentConfigOverlay { identity: Record; adapterType?: string; adapterConfig: Record; heartbeat: Record; runtime: Record; } const ADAPTER_AGNOSTIC_KEYS = [ "env", "promptTemplate", "instructionsFilePath", "cwd", "timeoutSec", "graceSec", "bootstrapPromptTemplate", ] as const; 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 (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) { const existingRc = (agent.runtimeConfig ?? {}) as Record; const existingHb = (existingRc.heartbeat ?? {}) as Record; patch.runtimeConfig = { ...existingRc, heartbeat: { ...existingHb, ...overlay.heartbeat } }; } if (Object.keys(overlay.runtime).length > 0) { Object.assign(patch, overlay.runtime); } return patch; }