fix(server): a plugin that stops reporting an option has reset it

The adapter only visited keys present in a new report, so a key the plugin
dropped to return to its default kept its stored value and its rewind value.
A previously reported key that disappears is now reported as removed.
This commit is contained in:
Mohamed Boudra
2026-11-02 01:01:24 +01:00
parent 5b4636b856
commit 25a3efe0ac
2 changed files with 29 additions and 0 deletions
@@ -1209,6 +1209,30 @@ describe("PluginAgentClientRegistry", () => {
await session.close();
});
test.runIf(shape === "controls")(
"reports an option the plugin stops reporting as removed, alone or with another change",
async () => {
const { session, events, changeOnItsOwn } = await openStubbornVoiceSession({});
changeOnItsOwn({ tokenBudget: 500 });
changeOnItsOwn({ tokenBudget: undefined });
changeOnItsOwn({ tokenBudget: 700 });
changeOnItsOwn({ tokenBudget: undefined, loud: true });
expect(eventsOfType(events, "options_changed")).toEqual([
{ type: "options_changed", provider: "plugin-direct", patch: { token_budget: 500 } },
{ type: "options_changed", provider: "plugin-direct", patch: { token_budget: null } },
{ type: "options_changed", provider: "plugin-direct", patch: { token_budget: 700 } },
{
type: "options_changed",
provider: "plugin-direct",
patch: { token_budget: null, loud: true },
},
]);
await session.close();
},
);
test("a rejected apply reports what the plugin moved before refusing, since nothing is stored", async () => {
const { session, events } = await openStubbornVoiceSession({}, { refuseAfterChanging: true });
@@ -1675,6 +1675,11 @@ class PluginAgentSession implements AgentSession {
private reportOptionChanges(): AgentStreamEvent[] {
if (this.applyingOptions) return [];
const patch = this.optionDifferences(this.knownOptions);
// A key the plugin reported before and no longer reports went back to its default.
const current = this.currentOptions();
for (const id of Object.keys(this.knownOptions)) {
if (!(id in current)) patch[id] = null;
}
if (Object.keys(patch).length === 0) return [];
this.commitOptions();
return [{ type: "options_changed", provider: this.provider, patch }];