From 2ec765edeafa5d4ce01ae07be85307aac3c5aa50 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 4 Jul 2026 22:57:11 -0400 Subject: [PATCH] fix(auto-reply): deliver model directive acknowledgements (#100151) --- ...et-reply-directives.target-session.test.ts | 21 +++++++++++++++++++ src/auto-reply/reply/get-reply-directives.ts | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/auto-reply/reply/get-reply-directives.target-session.test.ts b/src/auto-reply/reply/get-reply-directives.target-session.test.ts index b31d9dfc0081..548a2b058af0 100644 --- a/src/auto-reply/reply/get-reply-directives.target-session.test.ts +++ b/src/auto-reply/reply/get-reply-directives.target-session.test.ts @@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { SessionEntry } from "../../config/sessions.js"; import { SessionWorkStartInvalidatedError } from "../../config/sessions/lifecycle.js"; +import { getReplyPayloadMetadata } from "../reply-payload.js"; import type { TemplateContext } from "../templating.js"; import { resolveReplyDirectives } from "./get-reply-directives.js"; import { buildTestCtx } from "./test-ctx.js"; @@ -369,6 +370,26 @@ describe("resolveReplyDirectives", () => { expect(mocks.applyInlineDirectiveOverrides).not.toHaveBeenCalled(); }); + it("marks terminal directive replies for delivery under source suppression", async () => { + mocks.applyInlineDirectiveOverrides.mockResolvedValueOnce({ + kind: "reply", + reply: { text: "Model set to fable (anthropic/claude-fable-5) for this session." }, + }); + + const { result } = await resolveHelloWithModelDefaults({ + body: "/model fable", + commandAuthorized: true, + defaultThinking: "off", + defaultReasoning: "on", + }); + + expect(result.kind).toBe("reply"); + if (result.kind !== "reply" || !result.reply || Array.isArray(result.reply)) { + throw new Error("expected a single directive reply"); + } + expect(getReplyPayloadMetadata(result.reply)?.deliverDespiteSourceReplySuppression).toBe(true); + }); + it("keeps one-turn fast mode with the resolved fast mode", async () => { const { result } = await resolveHelloWithModelDefaults({ defaultThinking: "off", diff --git a/src/auto-reply/reply/get-reply-directives.ts b/src/auto-reply/reply/get-reply-directives.ts index 45b1e229af7c..3e10e9e8d32a 100644 --- a/src/auto-reply/reply/get-reply-directives.ts +++ b/src/auto-reply/reply/get-reply-directives.ts @@ -15,6 +15,7 @@ import { normalizeAgentId } from "../../routing/session-key.js"; import { createLazyImportLoader } from "../../shared/lazy-promise.js"; import type { SkillCommandSpec } from "../../skills/types.js"; import { shouldHandleTextCommands } from "../commands-text-routing.js"; +import { markCommandReplyForDelivery } from "../reply-payload.js"; import type { MsgContext, TemplateContext } from "../templating.js"; import { normalizeThinkLevel, @@ -651,7 +652,7 @@ export async function resolveReplyDirectives(params: { typing, }); if (applyResult.kind === "reply") { - return { kind: "reply", reply: applyResult.reply }; + return { kind: "reply", reply: markCommandReplyForDelivery(applyResult.reply) }; } directives = applyResult.directives; provider = applyResult.provider;