fix(agents): retain intentional card edits in the dashboard

This commit is contained in:
Joshua Valluru 2026-09-30 14:04:26 -07:00
parent 1cdc43665c
commit a168eaa98b
3 changed files with 24 additions and 4 deletions

View file

@ -92,9 +92,10 @@ export const withAgentIdentity = (
payload: AgentRequestPayload,
values: AgentFormValues,
existing?: Partial<AgentIdentityState>,
cardEdited = false,
): AgentRequestPayload => {
const { agent_card_params, ...settings } = payload;
const hasCard = !existing || Object.keys(existing.agent_card_params ?? {}).length > 0;
const hasCard = !existing || cardEdited || Object.keys(existing.agent_card_params ?? {}).length > 0;
const identityFields = buildIdentityParams(values, existing?.identity);
const managed = values.identity_provider === "microsoft_entra" || Boolean(readAgentIdentity(existing?.identity));
return {

View file

@ -156,7 +156,11 @@ describe("AgentInfoView update payload", () => {
.mockResolvedValue({} as never);
});
it.each(["complete", "empty"])("preserves the Entra binding while renaming an agent with a %s card", async (card) => {
it.each([
{ card: "complete", editCard: false },
{ card: "empty", editCard: false },
{ card: "empty", editCard: true },
])("preserves identity and runtime intent with a $card card (card edits: $editCard)", async ({ card, editCard }) => {
const user = setup();
const identity = {
provider: "microsoft_entra",
@ -188,10 +192,20 @@ describe("AgentInfoView update payload", () => {
expect(screen.getByRole("combobox", { name: "Execution Mode" })).toHaveTextContent("Autonomous");
expect(screen.getByRole("combobox", { name: /^Execution$/ })).toHaveTextContent("Enabled");
fireEvent.change(screen.getByLabelText("Agent Name"), { target: { value: "Renamed agent" } });
if (editCard) {
fireEvent.change(screen.getByLabelText("Display Name"), { target: { value: "Configured runtime" } });
fireEvent.change(screen.getByLabelText("URL"), { target: { value: "https://runtime.example/a2a" } });
}
await save(user);
expect(patchedPayload().agent_name).toBe("Renamed agent");
expect(patchedPayload()).not.toHaveProperty("litellm_params");
expect(patchedPayload().agent_card_params === undefined).toBe(card === "empty");
expect(patchedPayload().agent_card_params === undefined).toBe(card === "empty" && !editCard);
if (editCard) {
expect(patchedPayload().agent_card_params).toMatchObject({
name: "Configured runtime",
url: "https://runtime.example/a2a",
});
}
expect(patchedPayload().identity).toMatchObject(identity);
expect(patchedPayload().access_group_ids).toEqual(["ag-entra"]);
expect(networking.patchAgentCall).toHaveBeenCalledWith(

View file

@ -238,9 +238,14 @@ const AgentInfoView: React.FC<AgentInfoViewProps> = ({ agentId, onClose, accessT
const updateData = appliedDiscoveredSelection
? overlayDiscoveredCardParams(built, appliedDiscoveredSelection.selected_card)
: built;
const cardEdited =
Boolean(appliedDiscoveredSelection) ||
[AGENT_FORM_CONFIG.basic, AGENT_FORM_CONFIG.skills, AGENT_FORM_CONFIG.capabilities, AGENT_FORM_CONFIG.optional]
.flatMap((section) => section.fields)
.some((field) => form.getFieldState(field.name).isDirty);
await patchAgentCall(accessToken, agentId, {
...withAgentIdentity(updateData, values, agent),
...withAgentIdentity(updateData, values, agent, cardEdited),
object_permission: buildMcpObjectPermission(values),
access_group_ids: values.access_group_ids ?? [],
});