mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 12:04:41 +01:00
Add harness-scoped bulk connection and default-model edits to the agent roster, with compatible choices, change previews, per-agent save results, and retries. Use an icon-based harness filter, keep agent rows readable, remove the status selector and selection hint, and redirect legacy status URLs to the full roster. Preserve authorization, audit history, unrelated settings, and optimistic concurrency checks through the existing agent update route. Co-Authored-By: Paperclip <noreply@paperclip.ing>
30 lines
2.0 KiB
TypeScript
30 lines
2.0 KiB
TypeScript
import { isDeepStrictEqual } from "node:util";
|
|
import { agentRuntimeSettingsHarness, type UpdateAgent } from "@paperclipai/shared";
|
|
import type { AgentConfigurationRecord } from "../lib/agent-records.js";
|
|
import { conflict, unprocessable } from "../errors.js";
|
|
|
|
/** Translate a scoped edit into the existing validated configuration write. */
|
|
export function prepareRuntimeSettingsPatch(existing: Pick<AgentConfigurationRecord, "adapterType" | "adapterConfig" | "runtimeConfig" | "status">, input: UpdateAgent): Record<string, unknown> {
|
|
const settings = input.runtimeSettings!;
|
|
if (Object.keys(input).some(key => key !== "runtimeSettings")) {
|
|
throw unprocessable("Runtime settings cannot be combined with other agent changes");
|
|
}
|
|
const harness = agentRuntimeSettingsHarness(existing.adapterType, existing.adapterConfig);
|
|
if (harness !== settings.harness) throw conflict("This agent's harness changed. Refresh the roster and select it again.");
|
|
if (["process", "http"].includes(harness) || ["terminated", "pending_approval"].includes(existing.status)) {
|
|
throw unprocessable("This agent cannot be updated from the roster");
|
|
}
|
|
const model = typeof existing.adapterConfig.model === "string" ? existing.adapterConfig.model.trim() || null : null;
|
|
const binding = existing.runtimeConfig.aiConnection ?? null;
|
|
if (model !== settings.expected.model || !isDeepStrictEqual(binding, settings.expected.aiConnection)) {
|
|
throw conflict("This agent's connection or model changed. Refresh the roster and review the changes again.");
|
|
}
|
|
if (settings.aiConnection?.mode === "router" || (binding && typeof binding === "object" && "mode" in binding && binding.mode === "router")) {
|
|
throw unprocessable("Edit connection pool members on the agent's configuration page");
|
|
}
|
|
return {
|
|
...(settings.model !== undefined ? { adapterConfig: { model: settings.model } } : {}),
|
|
...(settings.aiConnection !== undefined ? { runtimeConfig: { ...existing.runtimeConfig, aiConnection: settings.aiConnection } } : {}),
|
|
};
|
|
}
|