From e736fcfa096d75b6ee7e33ff09b77e3c1aef6a4b Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Sun, 16 Aug 2026 22:02:54 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20refactor:=20Keep=20Agen?= =?UTF-8?q?t=20Conversations=20From=20Revealing=20Model=20Labels=20(#14909?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/Chat/Input/AddedConvo.tsx | 14 ++++++++------ .../Conversations/__tests__/useGetSender.spec.tsx | 15 +++++++++++++++ client/src/hooks/Conversations/useGetSender.ts | 9 ++++++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/client/src/components/Chat/Input/AddedConvo.tsx b/client/src/components/Chat/Input/AddedConvo.tsx index 764612ec90..89e26b562f 100644 --- a/client/src/components/Chat/Input/AddedConvo.tsx +++ b/client/src/components/Chat/Input/AddedConvo.tsx @@ -5,6 +5,7 @@ import type { SetterOrUpdater } from 'recoil'; import { useGetEndpointsQuery } from '~/data-provider'; import { EndpointIcon } from '~/components/Endpoints'; import { useAgentsMapContext } from '~/Providers'; +import { useLocalize } from '~/hooks'; export default function AddedConvo({ addedConvo, @@ -15,13 +16,14 @@ export default function AddedConvo({ }) { const agentsMap = useAgentsMapContext(); const { data: endpointsConfig } = useGetEndpointsQuery(); + const localize = useLocalize(); const title = useMemo(() => { // Priority: agent name > modelDisplayLabel > modelLabel > model - if (isAgentsEndpoint(addedConvo?.endpoint) && addedConvo?.agent_id) { - const agent = agentsMap?.[addedConvo.agent_id]; - if (agent?.name) { - return `+ ${agent.name}`; - } + if (isAgentsEndpoint(addedConvo?.endpoint)) { + const agent = addedConvo?.agent_id ? agentsMap?.[addedConvo.agent_id] : undefined; + /** Never fall into the model-label chain for agents — it would reveal the + * underlying model an agent author may intend to keep private. */ + return `+ ${agent?.name || localize('com_ui_agent')}`; } const endpointConfig = endpointsConfig?.[addedConvo?.endpoint ?? '']; @@ -29,7 +31,7 @@ export default function AddedConvo({ endpointConfig?.modelDisplayLabel || addedConvo?.modelLabel || addedConvo?.model || 'AI'; return `+ ${displayLabel}`; - }, [addedConvo, agentsMap, endpointsConfig]); + }, [addedConvo, agentsMap, endpointsConfig, localize]); if (!addedConvo) { return null; diff --git a/client/src/hooks/Conversations/__tests__/useGetSender.spec.tsx b/client/src/hooks/Conversations/__tests__/useGetSender.spec.tsx index efba85a76b..cc48f374a3 100644 --- a/client/src/hooks/Conversations/__tests__/useGetSender.spec.tsx +++ b/client/src/hooks/Conversations/__tests__/useGetSender.spec.tsx @@ -91,4 +91,19 @@ describe('useGetSender', () => { }; expect(getSender(asOption(unknownCustom))).toBe(getResponseSender(asOption(unknownCustom))); }); + + it('never reveals model or spec labels for agent conversations', () => { + const getSender = renderGetSender(); + expect( + getSender( + asOption({ + endpoint: EModelEndpoint.agents, + agent_id: 'agent_abc123', + model: 'gpt-5.5', + modelLabel: 'GPT-5.5 Pro', + spec: 'fast-qwen', + }), + ), + ).toBe(''); + }); }); diff --git a/client/src/hooks/Conversations/useGetSender.ts b/client/src/hooks/Conversations/useGetSender.ts index 1f978049fa..a3b17d04cf 100644 --- a/client/src/hooks/Conversations/useGetSender.ts +++ b/client/src/hooks/Conversations/useGetSender.ts @@ -1,5 +1,5 @@ import { useCallback } from 'react'; -import { getResponseSender, getEphemeralSender } from 'librechat-data-provider'; +import { getResponseSender, getEphemeralSender, isAgentsEndpoint } from 'librechat-data-provider'; import type { TEndpointOption, TEndpointsConfig } from 'librechat-data-provider'; import { useGetEndpointsQuery, useGetStartupConfig } from '~/data-provider'; import { getModelSpec } from '~/utils'; @@ -8,6 +8,10 @@ import { getModelSpec } from '~/utils'; * Mirrors the server's sender resolution (`modelLabel` → spec label → endpoint * `modelDisplayLabel` → `getResponseSender`) so the optimistic streaming label * and composer placeholder match the persisted `message.sender`. + * + * Agent conversations are exempt from the label chain: their display name is + * the agent's, and surfacing model or spec labels would reveal the underlying + * model an agent author may intend to keep private. */ export default function useGetSender() { const { data: startupConfig } = useGetStartupConfig(); @@ -15,6 +19,9 @@ export default function useGetSender() { return useCallback( (endpointOption: TEndpointOption) => { const { modelDisplayLabel } = endpointsConfig?.[endpointOption.endpoint ?? ''] ?? {}; + if (isAgentsEndpoint(endpointOption.endpoint)) { + return getResponseSender({ ...endpointOption, modelDisplayLabel }); + } const modelSpec = getModelSpec({ specName: endpointOption.spec, startupConfig }); const sender = getEphemeralSender({ modelLabel: endpointOption.modelLabel,