fix(plugins): a plugin reporting settings is sent every key of an options patch

This commit is contained in:
Mohamed Boudra
2026-11-06 04:50:52 +01:00
parent 746165c300
commit 2d976b0b19
3 changed files with 8 additions and 14 deletions
+1 -1
View File
@@ -544,7 +544,7 @@ The provider draws some of those keys in the composer by reporting `controls` an
built-in providers ([options flow](providers.md#options-flow)). `PluginAgentSession` in
`packages/server/src/server/agent/plugin-provider.ts` is that adapter. A provider still reporting
`settings` is read through `plugin-provider-options.ts`, which turns each setting into a control and
its value into an option and is sent both shapes in `session.configure` (`settings` holds only the keys it reports); delete it with
its value into an option and is sent both shapes in `session.configure`; delete it with
`COMPAT(plugin-provider-settings)`. The ACP shim still reports `settings`.
Providers add an optional veto to daemon baseline cleanup through the per-session
@@ -1481,8 +1481,10 @@ describe("PluginAgentClientRegistry", () => {
changes: { providerOptions: object; settings?: object };
};
expect(configure.changes.providerOptions).toEqual({ loud: true, launch_key: "changed" });
// A plugin reporting `settings` reads only the ones it reports.
expect(configure.changes.settings).toEqual(shape === "settings" ? { loud: true } : undefined);
// A plugin reporting `settings` is sent the same keys under that name.
expect(configure.changes.settings).toEqual(
shape === "settings" ? { loud: true, launch_key: "changed" } : undefined,
);
await session.close();
});
@@ -1430,7 +1430,7 @@ class PluginAgentSession implements AgentSession {
private async applyOptionsNow(options: ProviderOptions): Promise<Record<string, JsonValue>> {
this.assertReplayComplete();
const before = this.currentOptions();
const { controls, legacySettings } = readPluginOptionState(this.bridge.config);
const { legacySettings } = readPluginOptionState(this.bridge.config);
// The plugin applies every key it is given or rejects the whole request.
const settings: Record<string, JsonValue> = {};
for (const [id, value] of Object.entries(options)) {
@@ -1440,18 +1440,10 @@ class PluginAgentSession implements AgentSession {
this.applyingOptions = true;
try {
// COMPAT(plugin-provider-settings): added in v0.15.0, remove after 2027-05-01. A plugin
// reporting `settings` reads only its own settings, so it is sent those.
// reporting `settings` is sent the same keys under that name.
await this.bridge.configure({
providerOptions: settings,
...(legacySettings
? {
settings: Object.fromEntries(
Object.entries(settings).filter(([id]) =>
controls.some((control) => control.key === id),
),
),
}
: {}),
...(legacySettings ? { settings } : {}),
});
} catch (error) {
// Nothing is stored for a refused patch, so what the plugin moved is reported once the