fix(rpc): honored todo setting opt-outs

Preserved project-level todo.enabled, todo.reminders, and todo.eager settings in protocol hosts instead of forcing host defaults.\n\nFixes #2824
This commit is contained in:
roboomp
2026-06-17 03:30:40 +00:00
parent 8eeb707387
commit 80cfc4737c
3 changed files with 79 additions and 4 deletions
+2
View File
@@ -43,6 +43,8 @@
- Fixed startup model fallback choosing the plain OpenAI `gpt-5.5` provider before the Codex OAuth provider when both shared the same default model id, which could surface a misleading OpenAI 401 despite valid Codex credentials ([#2807](https://github.com/can1357/oh-my-pi/issues/2807)).
- Fixed local auto-thinking classification for reasoning-capable tiny models by giving them the same safe answer budget as online reasoning classifiers, with a larger local floor for non-reasoning tiny models ([#2808](https://github.com/can1357/oh-my-pi/issues/2808)).
- Fixed RPC/ACP startup forcing todo settings back to host defaults, so project-level `todo.enabled`, `todo.reminders`, and `todo.eager` opt-outs now suppress protocol-mode todo prompt injection ([#2824](https://github.com/can1357/oh-my-pi/issues/2824)).
### Removed
- Removed the built-in `render_mermaid` tool and its `renderMermaid.enabled` setting, so it can no longer be invoked directly
+2 -4
View File
@@ -124,11 +124,9 @@ async function checkForNewVersion(currentVersion: string): Promise<string | unde
}
}
// Todo settings are caller-controlled in protocol modes. Do not host-default them:
// embedders need project-level opt-outs for reminder/prelude prompt injection.
const HOST_DEFAULTED_SETTING_PATHS: SettingPath[] = [
"todo.enabled",
"todo.reminders",
"todo.reminders.max",
"todo.eager",
"task.isolation.mode",
"task.isolation.merge",
"task.isolation.commits",
@@ -317,6 +317,81 @@ describe("ACP lazy startup", () => {
});
}
});
it("honors explicit todo settings for protocol hosts", async () => {
const { runRootCommand } = await import("@oh-my-pi/pi-coding-agent/main");
type ObservedTodoSettings = {
enabled: boolean;
reminders: boolean;
eager: "default" | "preferred" | "always";
};
const runProtocolStartup = async (mode: "rpc" | "rpc-ui" | "acp"): Promise<ObservedTodoSettings> => {
using tempDir = TempDir.createSync("@omp-protocol-todo-settings-");
const cwd = tempDir.path();
const authStorage = await AuthStorage.create(path.join(cwd, "auth.db"));
const settings = Settings.isolated({
"todo.enabled": false,
"todo.reminders": false,
"todo.eager": "always",
});
let observed: ObservedTodoSettings | undefined;
const stopMessage = "stop test protocol todo settings";
const observe = () => {
observed = {
enabled: settings.get("todo.enabled"),
reminders: settings.get("todo.reminders"),
eager: settings.get("todo.eager"),
};
throw new Error(stopMessage);
};
try {
await runRootCommand(
{
mode,
messages: [],
fileArgs: [],
unknownFlags: new Map(),
unrecognizedFlags: [],
noSkills: true,
noRules: true,
noTools: true,
noLsp: true,
noExtensions: true,
sessionDir: cwd,
},
[],
{
discoverAuthStorage: async () => authStorage,
settings,
createAgentSession: async () => observe(),
runAcpMode: async () => observe(),
},
);
} catch (error) {
if (!(error instanceof Error) || error.message !== stopMessage) {
throw error;
}
} finally {
authStorage.close();
}
if (!observed) {
throw new Error("Expected protocol mode to start");
}
return observed;
};
for (const mode of ["rpc", "rpc-ui", "acp"] as const) {
await expect(runProtocolStartup(mode)).resolves.toEqual({
enabled: false,
reminders: false,
eager: "always",
});
}
});
it("answers initialize before creating the first AgentSession", async () => {
const clientToAgent = new TransformStream();
const agentToClient = new TransformStream();