Component
Dictionary helper (src/helpers/agentNameDictionary.js)
Description & Actual Behavior
When agentNameDictionaryChanges(dictionary, newName, oldName) processes agent name updates, it trims newName for insertion but checks oldName without trimming against newName and dictionary.
This leads to two correctness defects:
- Accidental Deletion of Agent Name: When
oldName is "MyAgent" and newName is " MyAgent " (or vice versa), newName.trim() equals "MyAgent". Because words.includes("MyAgent") is true, add becomes []. However, oldName !== newName ("MyAgent" !== " MyAgent ") evaluates to true and words.includes(oldName) evaluates to true, causing remove to return ["MyAgent"]. The function returns { add: [], remove: ["MyAgent"] }, wiping the agent's name from the custom dictionary simply because surrounding whitespace was introduced in the name field.
- Orphaned Dictionary Entries on Rename: When
oldName has surrounding whitespace (e.g. " MyAgent ") and the user renames the agent to "NewAgent", oldName !== newName is true but words.includes(" MyAgent ") fails (since dictionary words are stored trimmed as "MyAgent"). As a result, remove returns [] and { add: ["NewAgent"], remove: [] }, leaving the old agent name orphaned in SQLite.
Expected Behavior
agentNameDictionaryChanges should normalize both newName and oldName by trimming whitespace before checking equality and dictionary presence.
- Renaming
"OpenWhispr" to " OpenWhispr " should yield { add: [], remove: [] }.
- Renaming
" OpenWhispr " to "Jarvis" when dictionary has ["OpenWhispr"] should yield { add: ["Jarvis"], remove: ["OpenWhispr"] }.
Reproduction
const { agentNameDictionaryChanges } = await import("./src/helpers/agentNameDictionary.js");
// Case 1: Agent name wiped on whitespace update
const r1 = agentNameDictionaryChanges(["MyAgent"], " MyAgent ", "MyAgent");
console.log(r1); // Actual: { add: [], remove: ['MyAgent'] } | Expected: { add: [], remove: [] }
// Case 2: Old agent name orphaned on rename with untrimmed oldName
const r2 = agentNameDictionaryChanges(["MyAgent"], "Jarvis", " MyAgent ");
console.log(r2); // Actual: { add: ['Jarvis'], remove: [] } | Expected: { add: ['Jarvis'], remove: ['MyAgent'] }
Environment
- OpenWhispr main branch
- Node.js 24+
User Impact
Updating or editing agent names in settings can silently wipe the agent's name from the custom dictionary or leave stale/orphaned names in the dictionary table.
Root-Cause Hypothesis
agentNameDictionaryChanges compares raw oldName against raw newName and checks words.includes(oldName) without trimming oldName first or comparing their trimmed forms.
Proposed Scope
Normalize newName and oldName using trim() before checking string equality and dictionary membership in agentNameDictionaryChanges. Add regression tests covering untrimmed inputs and whitespace-only name updates.
I intend to work on this issue and submit a pull request.
Component
Dictionary helper (
src/helpers/agentNameDictionary.js)Description & Actual Behavior
When
agentNameDictionaryChanges(dictionary, newName, oldName)processes agent name updates, it trimsnewNamefor insertion but checksoldNamewithout trimming againstnewNameanddictionary.This leads to two correctness defects:
oldNameis"MyAgent"andnewNameis" MyAgent "(or vice versa),newName.trim()equals"MyAgent". Becausewords.includes("MyAgent")is true,addbecomes[]. However,oldName !== newName("MyAgent" !== " MyAgent ") evaluates totrueandwords.includes(oldName)evaluates totrue, causingremoveto return["MyAgent"]. The function returns{ add: [], remove: ["MyAgent"] }, wiping the agent's name from the custom dictionary simply because surrounding whitespace was introduced in the name field.oldNamehas surrounding whitespace (e.g." MyAgent ") and the user renames the agent to"NewAgent",oldName !== newNameis true butwords.includes(" MyAgent ")fails (since dictionary words are stored trimmed as"MyAgent"). As a result,removereturns[]and{ add: ["NewAgent"], remove: [] }, leaving the old agent name orphaned in SQLite.Expected Behavior
agentNameDictionaryChangesshould normalize bothnewNameandoldNameby trimming whitespace before checking equality and dictionary presence."OpenWhispr"to" OpenWhispr "should yield{ add: [], remove: [] }." OpenWhispr "to"Jarvis"when dictionary has["OpenWhispr"]should yield{ add: ["Jarvis"], remove: ["OpenWhispr"] }.Reproduction
Environment
User Impact
Updating or editing agent names in settings can silently wipe the agent's name from the custom dictionary or leave stale/orphaned names in the dictionary table.
Root-Cause Hypothesis
agentNameDictionaryChangescompares rawoldNameagainst rawnewNameand checkswords.includes(oldName)without trimmingoldNamefirst or comparing their trimmed forms.Proposed Scope
Normalize
newNameandoldNameusingtrim()before checking string equality and dictionary membership inagentNameDictionaryChanges. Add regression tests covering untrimmed inputs and whitespace-only name updates.I intend to work on this issue and submit a pull request.