mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-27 17:58:07 +00:00
fix(desktop): submit only edited fields from the full-config modal
Unstored fields render their schema default, and 'Save all' persisted every one of them — pinning values that runtime defaults still own. Concretely: an existing Honcho user without an explicit observationMode runs 'unified' via the client's migration guard, but one untouched save-all flipped them to the schema's 'directional'. Diff against the seeded snapshot and submit only what the user changed.
This commit is contained in:
parent
a9cce6d844
commit
4d4db4281e
2 changed files with 15 additions and 13 deletions
|
|
@ -80,20 +80,15 @@ describe('ProviderConfigModal', () => {
|
|||
expect(screen.getByDisplayValue('{"t":"eri"}')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('saves all fields, serializing the toggled bool to "false"', async () => {
|
||||
it('saves only edited fields, serializing the toggled bool to "false"', async () => {
|
||||
const { onSaved, onOpenChange } = await renderModal()
|
||||
|
||||
fireEvent.click(await screen.findByRole('switch'))
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Save all' }))
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Save changes' }))
|
||||
|
||||
await waitFor(() =>
|
||||
expect(saveMemoryProviderConfig).toHaveBeenCalledWith('honcho', {
|
||||
workspace: 'myws',
|
||||
saveMessages: 'false',
|
||||
dialecticMaxChars: '1200',
|
||||
userPeerAliases: '{"t":"eri"}'
|
||||
})
|
||||
)
|
||||
// Untouched fields stay unsubmitted so a save never ratifies rendered
|
||||
// defaults the backend does not actually store.
|
||||
await waitFor(() => expect(saveMemoryProviderConfig).toHaveBeenCalledWith('honcho', { saveMessages: 'false' }))
|
||||
await waitFor(() => expect(onSaved).toHaveBeenCalled())
|
||||
expect(onOpenChange).toHaveBeenCalledWith(false)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -53,20 +53,27 @@ export function ProviderConfigModal({
|
|||
onSaved: () => Promise<void> | void
|
||||
}) {
|
||||
const [values, setValues] = useState<Record<string, string>>({})
|
||||
const [seeded, setSeeded] = useState<Record<string, string>>({})
|
||||
const [saving, setSaving] = useState(false)
|
||||
|
||||
// Reseed from the latest config each time the dialog opens so edits never
|
||||
// start from a stale snapshot left over from a prior session.
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setValues(seedAll(config))
|
||||
const seed = seedAll(config)
|
||||
setSeeded(seed)
|
||||
setValues(seed)
|
||||
}
|
||||
}, [open, config])
|
||||
|
||||
const save = async () => {
|
||||
// Unstored fields render their schema default; persisting untouched keys
|
||||
// would pin values that runtime defaults (e.g. migration guards) still own.
|
||||
const edited = Object.fromEntries(Object.entries(values).filter(([key, value]) => value !== seeded[key]))
|
||||
|
||||
setSaving(true)
|
||||
try {
|
||||
await saveMemoryProviderConfig(provider, values)
|
||||
await saveMemoryProviderConfig(provider, edited)
|
||||
notify({ kind: 'success', title: `${config.label} saved`, message: 'Memory provider configuration updated.' })
|
||||
await onSaved()
|
||||
onOpenChange(false)
|
||||
|
|
@ -138,7 +145,7 @@ export function ProviderConfigModal({
|
|||
</DialogClose>
|
||||
<Button disabled={saving} onClick={() => void save()} size="sm">
|
||||
{saving ? <Loader2 className="size-3.5 animate-spin" /> : <Save />}
|
||||
Save all
|
||||
Save changes
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue