From c421b2ac151d38abe3b0142e63720e6b2caad60b Mon Sep 17 00:00:00 2001 From: klopez4212 Date: Mon, 22 Jun 2026 08:39:05 +0100 Subject: [PATCH] Reset reused agent respond-to defaults --- .../features/agents/channelAgents.test.mjs | 77 +++++++++++++++++++ desktop/src/features/agents/channelAgents.ts | 48 ++++++++---- 2 files changed, 109 insertions(+), 16 deletions(-) create mode 100644 desktop/src/features/agents/channelAgents.test.mjs diff --git a/desktop/src/features/agents/channelAgents.test.mjs b/desktop/src/features/agents/channelAgents.test.mjs new file mode 100644 index 000000000..e8d7781a2 --- /dev/null +++ b/desktop/src/features/agents/channelAgents.test.mjs @@ -0,0 +1,77 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { respondToUpdateForReusedAgent } from "./channelAgents.ts"; + +const PUBKEY = "a".repeat(64); + +function agent(overrides = {}) { + return { + id: "agent-1", + pubkey: PUBKEY, + name: "Reusable", + personaId: "persona-1", + relayUrl: "ws://localhost:3000", + acpCommand: "buzz-acp", + agentCommand: "goose", + agentArgs: [], + mcpCommand: "", + turnTimeoutSeconds: 320, + idleTimeoutSeconds: null, + maxTurnDurationSeconds: null, + parallelism: 1, + systemPrompt: null, + avatarUrl: null, + model: null, + mcpToolsets: null, + envVars: {}, + status: "running", + pid: null, + createdAt: new Date(0).toISOString(), + updatedAt: new Date(0).toISOString(), + lastStartedAt: null, + lastStoppedAt: null, + lastExitCode: null, + lastError: null, + logPath: null, + startOnAppLaunch: false, + backend: { type: "local" }, + backendAgentId: null, + respondTo: "owner-only", + respondToAllowlist: [], + ...overrides, + }; +} + +test("respondToUpdateForReusedAgent resets omitted mode to owner-only", () => { + assert.deepEqual( + respondToUpdateForReusedAgent( + agent({ + respondTo: "anyone", + respondToAllowlist: [PUBKEY], + }), + {}, + ), + { + respondTo: "owner-only", + respondToAllowlist: [], + }, + ); +}); + +test("respondToUpdateForReusedAgent leaves matching owner-only agents unchanged", () => { + assert.equal(respondToUpdateForReusedAgent(agent(), {}), null); +}); + +test("respondToUpdateForReusedAgent carries explicit allowlist choices", () => { + assert.deepEqual( + respondToUpdateForReusedAgent(agent(), { + respondTo: "allowlist", + respondToAllowlist: [PUBKEY], + }), + { + respondTo: "allowlist", + respondToAllowlist: [PUBKEY], + }, + ); +}); diff --git a/desktop/src/features/agents/channelAgents.ts b/desktop/src/features/agents/channelAgents.ts index 48ddb4697..89a82f3e1 100644 --- a/desktop/src/features/agents/channelAgents.ts +++ b/desktop/src/features/agents/channelAgents.ts @@ -91,6 +91,32 @@ export type CreateChannelManagedAgentsResult = { failures: CreateChannelManagedAgentBatchFailure[]; }; +export function respondToUpdateForReusedAgent( + agent: ManagedAgent, + input: Pick< + CreateChannelManagedAgentInput, + "respondTo" | "respondToAllowlist" + >, +): Pick< + CreateChannelManagedAgentInput, + "respondTo" | "respondToAllowlist" +> | null { + const nextRespondTo = input.respondTo ?? "owner-only"; + const nextAllowlist = + nextRespondTo === "allowlist" ? (input.respondToAllowlist ?? []) : []; + const allowlistChanged = + agent.respondToAllowlist.join(",") !== nextAllowlist.join(","); + + if (agent.respondTo === nextRespondTo && !allowlistChanged) { + return null; + } + + return { + respondTo: nextRespondTo, + respondToAllowlist: nextAllowlist, + }; +} + export async function attachManagedAgentToChannel( channelId: string, input: AttachManagedAgentToChannelInput, @@ -273,17 +299,12 @@ export async function createChannelManagedAgent( if (reusable) { // Apply the caller's respondTo settings so the user's permission // choice in the dialog is always honored, even when reusing. - const needsRespondToUpdate = - input.respondTo && input.respondTo !== "owner-only"; - const updatedAgent = needsRespondToUpdate + const respondToUpdate = respondToUpdateForReusedAgent(reusable, input); + const updatedAgent = respondToUpdate ? ( await updateManagedAgent({ pubkey: reusable.pubkey, - respondTo: input.respondTo, - respondToAllowlist: - input.respondTo === "allowlist" - ? input.respondToAllowlist - : undefined, + ...respondToUpdate, }) ).agent : reusable; @@ -316,17 +337,12 @@ export async function createChannelManagedAgent( context.channelMemberPubkeys, ); if (reusable) { - const needsRespondToUpdate = - input.respondTo && input.respondTo !== "owner-only"; - const updatedAgent = needsRespondToUpdate + const respondToUpdate = respondToUpdateForReusedAgent(reusable, input); + const updatedAgent = respondToUpdate ? ( await updateManagedAgent({ pubkey: reusable.pubkey, - respondTo: input.respondTo, - respondToAllowlist: - input.respondTo === "allowlist" - ? input.respondToAllowlist - : undefined, + ...respondToUpdate, }) ).agent : reusable;