// @vitest-environment node import { describe, expect, it } from "vitest"; import type { Agent } from "@penclipai/shared"; import { buildAgentUpdatePatch, type AgentConfigOverlay } from "./agent-config-patch"; function makeAgent(): Agent { return { id: "agent-1", companyId: "company-1", name: "Agent", role: "engineer", title: "Engineer", icon: null, status: "active", reportsTo: null, capabilities: null, adapterType: "claude_local", adapterConfig: { model: "claude-sonnet-4-6", env: { OPENAI_API_KEY: { type: "plain", value: "secret", }, }, promptTemplate: "Work the issue.", }, runtimeConfig: { heartbeat: { enabled: true, intervalSec: 300, }, }, budgetMonthlyCents: 0, spentMonthlyCents: 0, pauseReason: null, pausedAt: null, lastHeartbeatAt: null, createdAt: new Date("2026-01-01T00:00:00.000Z"), updatedAt: new Date("2026-01-01T00:00:00.000Z"), urlKey: "agent", permissions: { canCreateAgents: false, }, metadata: null, }; } function makeOverlay(patch?: Partial): AgentConfigOverlay { return { identity: {}, adapterConfig: {}, heartbeat: {}, runtime: {}, ...patch, }; } describe("buildAgentUpdatePatch", () => { it("replaces adapter config and drops env when the last env binding is cleared", () => { const patch = buildAgentUpdatePatch( makeAgent(), makeOverlay({ adapterConfig: { env: undefined, }, }), ); expect(patch).toEqual({ adapterConfig: { model: "claude-sonnet-4-6", promptTemplate: "Work the issue.", }, replaceAdapterConfig: true, }); }); it("preserves adapter-agnostic keys when changing adapter types", () => { const patch = buildAgentUpdatePatch( makeAgent(), makeOverlay({ adapterType: "codex_local", adapterConfig: { model: "gpt-5.4", dangerouslyBypassApprovalsAndSandbox: true, }, }), ); expect(patch).toEqual({ adapterType: "codex_local", adapterConfig: { env: { OPENAI_API_KEY: { type: "plain", value: "secret", }, }, promptTemplate: "Work the issue.", model: "gpt-5.4", dangerouslyBypassApprovalsAndSandbox: true, }, replaceAdapterConfig: true, }); }); });