From d3c6d32cd0ffcaaf9534c352760427f335a01917 Mon Sep 17 00:00:00 2001 From: Jesse Merhi <79823012+jesse-merhi@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:23:52 +1000 Subject: [PATCH] fix(skills): scope inline markers to webchat --- ...ine-actions.skip-when-config-empty.test.ts | 42 ++++++++++++++++++- .../reply/get-reply-inline-actions.ts | 3 +- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts b/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts index 1942fbb1f6b8..cfb847d0dded 100644 --- a/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts +++ b/src/auto-reply/reply/get-reply-inline-actions.skip-when-config-empty.test.ts @@ -762,7 +762,12 @@ describe("handleInlineActions", () => { it("rewrites a skill marker embedded in normal prose", async () => { const typing = createTypingController(); const body = "Please use /office_hours: to build me a deployment plan"; - const ctx = buildTestCtx({ Body: body, CommandBody: body }); + const ctx = buildTestCtx({ + Body: body, + CommandBody: body, + Provider: "webchat", + Surface: "webchat", + }); const result = await handleInlineActions( createHandleInlineActionsInput({ @@ -796,7 +801,12 @@ describe("handleInlineActions", () => { it("keeps unauthorized inline skill markers as plain text", async () => { const typing = createTypingController(); const body = "Please use /office_hours: to build me a deployment plan"; - const ctx = buildTestCtx({ Body: body, CommandBody: body }); + const ctx = buildTestCtx({ + Body: body, + CommandBody: body, + Provider: "webchat", + Surface: "webchat", + }); const result = await handleInlineActions( createHandleInlineActionsInput({ @@ -821,6 +831,34 @@ describe("handleInlineActions", () => { expect(handleCommandsMock).not.toHaveBeenCalled(); }); + it("keeps authorized messaging-channel inline skill markers as plain text", async () => { + const typing = createTypingController(); + const body = "Please use /office_hours: to build me a deployment plan"; + const ctx = buildTestCtx({ Body: body, CommandBody: body }); + + const result = await handleInlineActions( + createHandleInlineActionsInput({ + ctx, + typing, + cleanedBody: body, + command: { + isAuthorizedSender: true, + rawBodyNormalized: body, + commandBodyNormalized: body, + }, + overrides: { + allowTextCommands: true, + cfg: { commands: { text: true } }, + skillCommands: officeHoursSkillCommands(), + }, + }), + ); + + expect(result).toMatchObject({ kind: "continue", cleanedBody: body }); + expect(ctx.Body).toBe(body); + expect(handleCommandsMock).not.toHaveBeenCalled(); + }); + it.each(["Review /tmp/foo before continuing", "/tmp/foo should stay a path"])( "does not load workspace skills for a bare path in %j", async (body) => { diff --git a/src/auto-reply/reply/get-reply-inline-actions.ts b/src/auto-reply/reply/get-reply-inline-actions.ts index 95e8b9fdc5cf..fffa3490d129 100644 --- a/src/auto-reply/reply/get-reply-inline-actions.ts +++ b/src/auto-reply/reply/get-reply-inline-actions.ts @@ -385,7 +385,8 @@ export async function handleInlineActions(params: { !skillInvocation && allowTextCommands && skillCommands.length > 0 && - command.isAuthorizedSender + command.isAuthorizedSender && + ctx.Surface === INTERNAL_MESSAGE_CHANNEL ) { skillInvocation = resolveInlineSkillCommandInvocation({ commandBodyNormalized: command.commandBodyNormalized,