mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-04 23:07:19 +02:00
🏷️ fix: Clear ModelSpec Display Fields When Navigating via Agent Share Link (#12274)
- Extract `specDisplayFieldReset` constant and `mergeQuerySettingsWithSpec` utility to `client/src/utils/endpoints.ts` as a single source of truth for spec display fields that must be cleared on non-spec transitions. - Clear `spec`, `iconURL`, `modelLabel`, and `greeting` from the merged preset in `ChatRoute.getNewConvoPreset()` when URL query parameters override the conversation without explicitly setting a spec. - Also clear `greeting` in the parallel cleanup in `useQueryParams.newQueryConvo` using the shared `specDisplayFieldReset` constant. - Guard the field reset on `specPreset != null` so null values aren't injected when no spec is configured. - Add comprehensive test coverage for the merge-and-clear logic.
This commit is contained in:
parent
9a64791e3e
commit
0c378811f1
4 changed files with 195 additions and 19 deletions
152
client/src/utils/__tests__/mergeQuerySettingsWithSpec.test.ts
Normal file
152
client/src/utils/__tests__/mergeQuerySettingsWithSpec.test.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import type { TPreset } from 'librechat-data-provider';
|
||||
import { mergeQuerySettingsWithSpec, specDisplayFieldReset } from '../endpoints';
|
||||
|
||||
describe('mergeQuerySettingsWithSpec', () => {
|
||||
const specPreset: TPreset = {
|
||||
endpoint: EModelEndpoint.openAI,
|
||||
model: 'gpt-4',
|
||||
spec: 'my-spec',
|
||||
iconURL: 'https://example.com/icon.png',
|
||||
modelLabel: 'My Custom GPT',
|
||||
greeting: 'Hello from the spec!',
|
||||
temperature: 0.7,
|
||||
};
|
||||
|
||||
describe('when specPreset is active and query has no spec', () => {
|
||||
it('clears all spec display fields for agent share links', () => {
|
||||
const querySettings: TPreset = {
|
||||
agent_id: 'agent_123',
|
||||
endpoint: EModelEndpoint.agents,
|
||||
};
|
||||
|
||||
const result = mergeQuerySettingsWithSpec(specPreset, querySettings);
|
||||
|
||||
expect(result.agent_id).toBe('agent_123');
|
||||
expect(result.endpoint).toBe(EModelEndpoint.agents);
|
||||
expect(result.spec).toBeNull();
|
||||
expect(result.iconURL).toBeNull();
|
||||
expect(result.modelLabel).toBeNull();
|
||||
expect(result.greeting).toBeUndefined();
|
||||
});
|
||||
|
||||
it('preserves non-display settings from the spec base', () => {
|
||||
const querySettings: TPreset = {
|
||||
agent_id: 'agent_123',
|
||||
endpoint: EModelEndpoint.agents,
|
||||
};
|
||||
|
||||
const result = mergeQuerySettingsWithSpec(specPreset, querySettings);
|
||||
|
||||
expect(result.temperature).toBe(0.7);
|
||||
});
|
||||
|
||||
it('clears spec display fields for assistant share links', () => {
|
||||
const querySettings: TPreset = {
|
||||
assistant_id: 'asst_abc',
|
||||
endpoint: EModelEndpoint.assistants,
|
||||
};
|
||||
|
||||
const result = mergeQuerySettingsWithSpec(specPreset, querySettings);
|
||||
|
||||
expect(result.assistant_id).toBe('asst_abc');
|
||||
expect(result.endpoint).toBe(EModelEndpoint.assistants);
|
||||
expect(result.spec).toBeNull();
|
||||
expect(result.iconURL).toBeNull();
|
||||
expect(result.modelLabel).toBeNull();
|
||||
expect(result.greeting).toBeUndefined();
|
||||
});
|
||||
|
||||
it('clears spec display fields for model override links', () => {
|
||||
const querySettings: TPreset = {
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
endpoint: EModelEndpoint.anthropic,
|
||||
};
|
||||
|
||||
const result = mergeQuerySettingsWithSpec(specPreset, querySettings);
|
||||
|
||||
expect(result.model).toBe('claude-sonnet-4-20250514');
|
||||
expect(result.endpoint).toBe(EModelEndpoint.anthropic);
|
||||
expect(result.spec).toBeNull();
|
||||
expect(result.iconURL).toBeNull();
|
||||
expect(result.modelLabel).toBeNull();
|
||||
expect(result.greeting).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when query explicitly sets a spec', () => {
|
||||
it('preserves spec display fields from the base', () => {
|
||||
const querySettings = { spec: 'other-spec' } as TPreset;
|
||||
|
||||
const result = mergeQuerySettingsWithSpec(specPreset, querySettings);
|
||||
|
||||
expect(result.spec).toBe('other-spec');
|
||||
expect(result.iconURL).toBe('https://example.com/icon.png');
|
||||
expect(result.modelLabel).toBe('My Custom GPT');
|
||||
expect(result.greeting).toBe('Hello from the spec!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when specPreset is undefined (no spec configured)', () => {
|
||||
it('returns querySettings without injecting null display fields', () => {
|
||||
const querySettings: TPreset = {
|
||||
agent_id: 'agent_123',
|
||||
endpoint: EModelEndpoint.agents,
|
||||
};
|
||||
|
||||
const result = mergeQuerySettingsWithSpec(undefined, querySettings);
|
||||
|
||||
expect(result.agent_id).toBe('agent_123');
|
||||
expect(result.endpoint).toBe(EModelEndpoint.agents);
|
||||
expect(result).not.toHaveProperty('spec');
|
||||
expect(result).not.toHaveProperty('iconURL');
|
||||
expect(result).not.toHaveProperty('modelLabel');
|
||||
expect(result).not.toHaveProperty('greeting');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when querySettings is empty', () => {
|
||||
it('still clears spec display fields (no query params is not an explicit spec)', () => {
|
||||
const result = mergeQuerySettingsWithSpec(specPreset, {} as TPreset);
|
||||
|
||||
expect(result.spec).toBeNull();
|
||||
expect(result.iconURL).toBeNull();
|
||||
expect(result.modelLabel).toBeNull();
|
||||
expect(result.greeting).toBeUndefined();
|
||||
expect(result.endpoint).toBe(EModelEndpoint.openAI);
|
||||
expect(result.model).toBe('gpt-4');
|
||||
expect(result.temperature).toBe(0.7);
|
||||
});
|
||||
});
|
||||
|
||||
describe('query settings override spec values', () => {
|
||||
it('overrides endpoint and model from spec', () => {
|
||||
const querySettings: TPreset = {
|
||||
endpoint: EModelEndpoint.anthropic,
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
};
|
||||
|
||||
const result = mergeQuerySettingsWithSpec(specPreset, querySettings);
|
||||
|
||||
expect(result.endpoint).toBe(EModelEndpoint.anthropic);
|
||||
expect(result.model).toBe('claude-sonnet-4-20250514');
|
||||
expect(result.temperature).toBe(0.7);
|
||||
expect(result.spec).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('specDisplayFieldReset', () => {
|
||||
it('contains all spec display fields that need clearing', () => {
|
||||
expect(specDisplayFieldReset).toEqual({
|
||||
spec: null,
|
||||
iconURL: null,
|
||||
modelLabel: null,
|
||||
greeting: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('has exactly 4 fields', () => {
|
||||
expect(Object.keys(specDisplayFieldReset)).toHaveLength(4);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue