From 8ba35a2dc3abd952b09cd44ad4799ff8574b12ff Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 3 Dec 2025 08:57:30 +0000 Subject: [PATCH] Auto-reply: treat prefixed think directives as directive-only --- src/auto-reply/reply.ts | 10 ++++++++- src/index.core.test.ts | 46 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/auto-reply/reply.ts b/src/auto-reply/reply.ts index 410d896d2..94ea4688e 100644 --- a/src/auto-reply/reply.ts +++ b/src/auto-reply/reply.ts @@ -224,8 +224,16 @@ export async function getReplyFromConfig( (sessionEntry?.thinkingLevel as ThinkLevel | undefined) ?? (reply?.thinkingDefault as ThinkLevel | undefined); + const directiveOnly = (() => { + if (!hasThinkDirective) return false; + if (!thinkCleaned) return true; + // Ignore bracketed prefixes (timestamps, same-phone markers, etc.) + const stripped = thinkCleaned.replace(/\[[^\]]+\]\s*/g, "").trim(); + return stripped.length === 0; + })(); + // Directive-only message => persist session thinking level and return ack - if (hasThinkDirective && !thinkCleaned) { + if (directiveOnly) { if (!inlineThink) { cleanupTyping(); return { diff --git a/src/index.core.test.ts b/src/index.core.test.ts index d29126568..fbcd1854b 100644 --- a/src/index.core.test.ts +++ b/src/index.core.test.ts @@ -641,6 +641,52 @@ describe("config and templating", () => { expect(ack?.text).toBe("Thinking level set to high."); }); + it("treats directive-only even when bracket prefixes are present", async () => { + const runSpy = vi.spyOn(index, "runCommandWithTimeout").mockResolvedValue({ + stdout: "ok", + stderr: "", + code: 0, + signal: null, + killed: false, + }); + const storeDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), "warelay-session-"), + ); + const storePath = path.join(storeDir, "sessions.json"); + const cfg = { + inbound: { + reply: { + mode: "command" as const, + command: ["echo", "{{Body}}"], + agent: { kind: "claude" }, + session: { store: storePath }, + }, + }, + }; + + const ack = await index.getReplyFromConfig( + { Body: "[Dec 1 00:00] [🦞 same-phone] /think:high", From: "+1", To: "+2" }, + undefined, + cfg, + runSpy, + ); + + expect(runSpy).not.toHaveBeenCalled(); + expect(ack?.text).toBe("Thinking level set to high."); + + await index.getReplyFromConfig( + { Body: "hello", From: "+1", To: "+2" }, + undefined, + cfg, + runSpy, + ); + + expect(runSpy).toHaveBeenCalledTimes(1); + const args = runSpy.mock.calls[0][0] as string[]; + const bodyArg = args[args.length - 1]; + expect(bodyArg).toBe("hello ultrathink"); + }); + it("rejects invalid directive-only think level without changing state", async () => { const runSpy = vi.spyOn(index, "runCommandWithTimeout").mockResolvedValue({ stdout: "ok",