🏷️ refactor: Keep Agent Conversations From Revealing Model Labels (#14909)

This commit is contained in:
Danny Avila 2026-08-16 22:02:54 -04:00 • committed by GitHub
parent e34d83bf7a
commit e736fcfa09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 31 additions and 7 deletions

View file

@ -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;

View file

@ -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('');
});
});

View file

@ -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,