fix(agents): gate auto reasoning by effective thinking level (openclaw#24335) thanks @Kay-051

This commit is contained in:
Nimrod Gutman
2026-02-23 14:58:26 +02:00
committed by Nimrod Gutman
parent 42795b87a3
commit 9d37654a90
3 changed files with 41 additions and 6 deletions

View File

@@ -244,7 +244,7 @@ describe("directive behavior", () => {
expect(call?.model).toBe("claude-opus-4-5");
});
});
it("defaults thinking to low for reasoning-capable models during normal replies", async () => {
it("defaults thinking to low for reasoning-capable models without auto-enabling reasoning", async () => {
await withTempHome(async (home) => {
mockEmbeddedTextResult("done");
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
@@ -269,6 +269,38 @@ describe("directive behavior", () => {
expect(runEmbeddedPiAgent).toHaveBeenCalledOnce();
const call = vi.mocked(runEmbeddedPiAgent).mock.calls[0]?.[0];
expect(call?.thinkLevel).toBe("low");
expect(call?.reasoningLevel).toBe("off");
});
});
it("keeps auto-reasoning enabled when thinking is explicitly off", async () => {
await withTempHome(async (home) => {
mockEmbeddedTextResult("done");
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
{
id: "claude-opus-4-5",
name: "Opus 4.5",
provider: "anthropic",
reasoning: true,
},
]);
await getReplyFromConfig(
{
Body: "hello",
From: "+1004",
To: "+2000",
},
{},
makeWhatsAppDirectiveConfig(home, {
model: { primary: "anthropic/claude-opus-4-5" },
thinkingDefault: "off",
}),
);
expect(runEmbeddedPiAgent).toHaveBeenCalledOnce();
const call = vi.mocked(runEmbeddedPiAgent).mock.calls[0]?.[0];
expect(call?.thinkLevel).toBe("off");
expect(call?.reasoningLevel).toBe("on");
});
});
it("passes elevated defaults when sender is approved", async () => {

View File

@@ -389,14 +389,16 @@ export async function resolveReplyDirectives(params: {
provider = modelState.provider;
model = modelState.model;
// When neither directive nor session set reasoning, default to model capability (e.g. OpenRouter with reasoning: true).
// Skip auto-enabling when thinking is already active — the model's internal
// thinking blocks would otherwise be formatted and delivered as visible
// "Reasoning:" messages, leaking internal content to the user.
// When neither directive nor session set reasoning, default to model capability
// (e.g. OpenRouter with reasoning: true). Skip auto-enabling when thinking is
// active, including model-inferred defaults, or internal thinking blocks can
// be emitted as visible "Reasoning:" messages.
const reasoningExplicitlySet =
directives.reasoningLevel !== undefined ||
(sessionEntry?.reasoningLevel !== undefined && sessionEntry?.reasoningLevel !== null);
const thinkingActive = resolvedThinkLevel !== undefined && resolvedThinkLevel !== "off";
const effectiveThinkingForReasoning =
resolvedThinkLevel ?? (await modelState.resolveDefaultThinkingLevel());
const thinkingActive = effectiveThinkingForReasoning !== "off";
if (!reasoningExplicitlySet && resolvedReasoningLevel === "off" && !thinkingActive) {
resolvedReasoningLevel = await modelState.resolveDefaultReasoningLevel();
}