fix: scope history injection to pending-only
This commit is contained in:
@@ -264,7 +264,7 @@ describe("monitorSlackProvider tool results", () => {
|
||||
expect(sendMock.mock.calls[1][1]).toBe("final reply");
|
||||
});
|
||||
|
||||
it("wraps room history in Body and preserves RawBody", async () => {
|
||||
it("preserves RawBody without injecting processed room history", async () => {
|
||||
config = {
|
||||
messages: { ackReactionScope: "group-mentions" },
|
||||
channels: {
|
||||
@@ -320,9 +320,9 @@ describe("monitorSlackProvider tool results", () => {
|
||||
await run;
|
||||
|
||||
expect(replyMock).toHaveBeenCalledTimes(2);
|
||||
expect(capturedCtx.Body).toContain(HISTORY_CONTEXT_MARKER);
|
||||
expect(capturedCtx.Body).toContain(CURRENT_MESSAGE_MARKER);
|
||||
expect(capturedCtx.Body).toContain("first");
|
||||
expect(capturedCtx.Body).not.toContain(HISTORY_CONTEXT_MARKER);
|
||||
expect(capturedCtx.Body).not.toContain(CURRENT_MESSAGE_MARKER);
|
||||
expect(capturedCtx.Body).not.toContain("first");
|
||||
expect(capturedCtx.RawBody).toBe("second");
|
||||
expect(capturedCtx.CommandBody).toBe("second");
|
||||
});
|
||||
@@ -334,7 +334,7 @@ describe("monitorSlackProvider tool results", () => {
|
||||
slack: {
|
||||
historyLimit: 5,
|
||||
dm: { enabled: true, policy: "open", allowFrom: ["*"] },
|
||||
channels: { C1: { allow: true, requireMention: false } },
|
||||
channels: { C1: { allow: true, requireMention: true } },
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -372,7 +372,7 @@ describe("monitorSlackProvider tool results", () => {
|
||||
event: {
|
||||
type: "message",
|
||||
user: "U1",
|
||||
text: "thread-a-two",
|
||||
text: "<@bot-user> thread-a-two",
|
||||
ts: "201",
|
||||
thread_ts: "100",
|
||||
channel: "C1",
|
||||
@@ -384,7 +384,7 @@ describe("monitorSlackProvider tool results", () => {
|
||||
event: {
|
||||
type: "message",
|
||||
user: "U2",
|
||||
text: "thread-b-one",
|
||||
text: "<@bot-user> thread-b-one",
|
||||
ts: "301",
|
||||
thread_ts: "300",
|
||||
channel: "C1",
|
||||
@@ -396,10 +396,10 @@ describe("monitorSlackProvider tool results", () => {
|
||||
controller.abort();
|
||||
await run;
|
||||
|
||||
expect(replyMock).toHaveBeenCalledTimes(3);
|
||||
expect(capturedCtx[1]?.Body).toContain("thread-a-one");
|
||||
expect(capturedCtx[2]?.Body).not.toContain("thread-a-one");
|
||||
expect(capturedCtx[2]?.Body).not.toContain("thread-a-two");
|
||||
expect(replyMock).toHaveBeenCalledTimes(2);
|
||||
expect(capturedCtx[0]?.Body).toContain("thread-a-one");
|
||||
expect(capturedCtx[1]?.Body).not.toContain("thread-a-one");
|
||||
expect(capturedCtx[1]?.Body).not.toContain("thread-a-two");
|
||||
});
|
||||
|
||||
it("updates assistant thread status when replies start", async () => {
|
||||
|
||||
@@ -66,8 +66,6 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
});
|
||||
};
|
||||
|
||||
let didSendReply = false;
|
||||
|
||||
// Create mutable context for response prefix template interpolation
|
||||
let prefixContext: ResponsePrefixContext = {
|
||||
identityName: resolveIdentityName(cfg, route.agentId),
|
||||
@@ -88,7 +86,6 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
textLimit: ctx.textLimit,
|
||||
replyThreadTs,
|
||||
});
|
||||
didSendReply = true;
|
||||
replyPlan.markSent();
|
||||
},
|
||||
onError: (err, info) => {
|
||||
@@ -136,7 +133,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
}
|
||||
|
||||
if (!queuedFinal) {
|
||||
if (prepared.isRoomish && ctx.historyLimit > 0 && didSendReply) {
|
||||
if (prepared.isRoomish && ctx.historyLimit > 0) {
|
||||
clearHistoryEntries({
|
||||
historyMap: ctx.channelHistories,
|
||||
historyKey: prepared.historyKey,
|
||||
@@ -168,7 +165,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
});
|
||||
}
|
||||
|
||||
if (prepared.isRoomish && ctx.historyLimit > 0 && didSendReply) {
|
||||
if (prepared.isRoomish && ctx.historyLimit > 0) {
|
||||
clearHistoryEntries({
|
||||
historyMap: ctx.channelHistories,
|
||||
historyKey: prepared.historyKey,
|
||||
|
||||
@@ -2,7 +2,10 @@ import { resolveAckReaction } from "../../../agents/identity.js";
|
||||
import { hasControlCommand } from "../../../auto-reply/command-detection.js";
|
||||
import { shouldHandleTextCommands } from "../../../auto-reply/commands-registry.js";
|
||||
import { formatAgentEnvelope, formatThreadStarterEnvelope } from "../../../auto-reply/envelope.js";
|
||||
import { buildHistoryContextFromMap } from "../../../auto-reply/reply/history.js";
|
||||
import {
|
||||
buildPendingHistoryContextFromMap,
|
||||
recordPendingHistoryEntry,
|
||||
} from "../../../auto-reply/reply/history.js";
|
||||
import { buildMentionRegexes, matchesMentionPatterns } from "../../../auto-reply/reply/mentions.js";
|
||||
import { logVerbose, shouldLogVerbose } from "../../../globals.js";
|
||||
import { enqueueSystemEvent } from "../../../infra/system-events.js";
|
||||
@@ -167,6 +170,19 @@ export async function prepareSlackMessage(params: {
|
||||
},
|
||||
});
|
||||
|
||||
const baseSessionKey = route.sessionKey;
|
||||
const threadTs = message.thread_ts;
|
||||
const hasThreadTs = typeof threadTs === "string" && threadTs.length > 0;
|
||||
const isThreadReply = hasThreadTs && (threadTs !== message.ts || Boolean(message.parent_user_id));
|
||||
const threadKeys = resolveThreadSessionKeys({
|
||||
baseSessionKey,
|
||||
threadId: isThreadReply ? threadTs : undefined,
|
||||
parentSessionKey: isThreadReply && ctx.threadInheritParent ? baseSessionKey : undefined,
|
||||
});
|
||||
const sessionKey = threadKeys.sessionKey;
|
||||
const historyKey =
|
||||
isThreadReply && ctx.threadHistoryScope === "thread" ? sessionKey : message.channel;
|
||||
|
||||
const mentionRegexes = buildMentionRegexes(cfg, route.agentId);
|
||||
const wasMentioned =
|
||||
opts.wasMentioned ??
|
||||
@@ -233,6 +249,28 @@ export async function prepareSlackMessage(params: {
|
||||
const effectiveWasMentioned = mentionGate.effectiveWasMentioned;
|
||||
if (isRoom && shouldRequireMention && mentionGate.shouldSkip) {
|
||||
ctx.logger.info({ channel: message.channel, reason: "no-mention" }, "skipping room message");
|
||||
if (ctx.historyLimit > 0) {
|
||||
const pendingText = (message.text ?? "").trim();
|
||||
const fallbackFile = message.files?.[0]?.name
|
||||
? `[Slack file: ${message.files[0].name}]`
|
||||
: message.files?.length
|
||||
? "[Slack file]"
|
||||
: "";
|
||||
const pendingBody = pendingText || fallbackFile;
|
||||
if (pendingBody) {
|
||||
recordPendingHistoryEntry({
|
||||
historyMap: ctx.channelHistories,
|
||||
historyKey,
|
||||
limit: ctx.historyLimit,
|
||||
entry: {
|
||||
sender: senderName,
|
||||
body: pendingBody,
|
||||
timestamp: message.ts ? Math.round(Number(message.ts) * 1000) : undefined,
|
||||
messageId: message.ts,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -277,16 +315,6 @@ export async function prepareSlackMessage(params: {
|
||||
: null;
|
||||
|
||||
const roomLabel = channelName ? `#${channelName}` : `#${message.channel}`;
|
||||
const historyEntry =
|
||||
isRoomish && ctx.historyLimit > 0
|
||||
? {
|
||||
sender: senderName,
|
||||
body: rawBody,
|
||||
timestamp: message.ts ? Math.round(Number(message.ts) * 1000) : undefined,
|
||||
messageId: message.ts,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const preview = rawBody.replace(/\s+/g, " ").slice(0, 160);
|
||||
const inboundLabel = isDirectMessage
|
||||
? `Slack DM from ${senderName}`
|
||||
@@ -297,18 +325,6 @@ export async function prepareSlackMessage(params: {
|
||||
? `slack:channel:${message.channel}`
|
||||
: `slack:group:${message.channel}`;
|
||||
|
||||
const baseSessionKey = route.sessionKey;
|
||||
const threadTs = message.thread_ts;
|
||||
const hasThreadTs = typeof threadTs === "string" && threadTs.length > 0;
|
||||
const isThreadReply = hasThreadTs && (threadTs !== message.ts || Boolean(message.parent_user_id));
|
||||
const threadKeys = resolveThreadSessionKeys({
|
||||
baseSessionKey,
|
||||
threadId: isThreadReply ? threadTs : undefined,
|
||||
parentSessionKey: isThreadReply && ctx.threadInheritParent ? baseSessionKey : undefined,
|
||||
});
|
||||
const sessionKey = threadKeys.sessionKey;
|
||||
const historyKey =
|
||||
isThreadReply && ctx.threadHistoryScope === "thread" ? sessionKey : message.channel;
|
||||
enqueueSystemEvent(`${inboundLabel}: ${preview}`, {
|
||||
sessionKey,
|
||||
contextKey: `slack:message:${message.channel}:${message.ts ?? "unknown"}`,
|
||||
@@ -324,11 +340,10 @@ export async function prepareSlackMessage(params: {
|
||||
|
||||
let combinedBody = body;
|
||||
if (isRoomish && ctx.historyLimit > 0) {
|
||||
combinedBody = buildHistoryContextFromMap({
|
||||
combinedBody = buildPendingHistoryContextFromMap({
|
||||
historyMap: ctx.channelHistories,
|
||||
historyKey,
|
||||
limit: ctx.historyLimit,
|
||||
entry: historyEntry,
|
||||
currentMessage: combinedBody,
|
||||
formatEntry: (entry) =>
|
||||
formatAgentEnvelope({
|
||||
|
||||
Reference in New Issue
Block a user