Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,20 @@ export const OpenAICompatible = ({
setCustomHeaders((prev) => prev.filter((_, i) => i !== index))
}, [])

// Helper to convert array of tuples to object

// Add effect to update the parent component's state when local headers change
useEffect(() => {
const timer = setTimeout(() => {
const currentConfigHeaders = apiConfiguration?.openAiHeaders || {}
const headerObject = convertHeadersToObject(customHeaders)
setApiConfigurationField("openAiHeaders", headerObject)

// Only update if the processed object is different from the current config.
if (JSON.stringify(currentConfigHeaders) !== JSON.stringify(headerObject)) {
setApiConfigurationField("openAiHeaders", headerObject)
}
}, 300)

return () => clearTimeout(timer)
}, [customHeaders, setApiConfigurationField])
}, [customHeaders, apiConfiguration?.openAiHeaders, setApiConfigurationField])

const handleInputChange = useCallback(
<K extends keyof ProviderSettings, E>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,60 @@ describe("OpenAICompatible Component - includeMaxTokens checkbox", () => {
})
})
})

describe("OpenAICompatible Component - Headers dirty state fix", () => {
const mockSetApiConfigurationField = vi.fn()
const mockOrganizationAllowList = {
allowAll: true,
providers: {},
}

beforeEach(() => {
vi.clearAllMocks()
vi.useFakeTimers()
})

afterEach(() => {
vi.useRealTimers()
})

it("should not call setApiConfigurationField when headers have not changed", async () => {
const apiConfiguration: Partial<ProviderSettings> = {
openAiHeaders: { "X-Test": "value" },
}

render(
<OpenAICompatible
apiConfiguration={apiConfiguration as ProviderSettings}
setApiConfigurationField={mockSetApiConfigurationField}
organizationAllowList={mockOrganizationAllowList}
/>,
)

// Wait for the debounced update
vi.advanceTimersByTime(350)

// setApiConfigurationField should NOT be called because the headers haven't changed
expect(mockSetApiConfigurationField).not.toHaveBeenCalledWith("openAiHeaders", expect.anything())
})

it("should not trigger dirty state on initial mount with empty headers", async () => {
const apiConfiguration: Partial<ProviderSettings> = {
openAiHeaders: {},
}

render(
<OpenAICompatible
apiConfiguration={apiConfiguration as ProviderSettings}
setApiConfigurationField={mockSetApiConfigurationField}
organizationAllowList={mockOrganizationAllowList}
/>,
)

// Wait for the debounced update
vi.advanceTimersByTime(350)

// setApiConfigurationField should NOT be called because the headers haven't changed
expect(mockSetApiConfigurationField).not.toHaveBeenCalledWith("openAiHeaders", expect.anything())
})
})
Loading