Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 33 additions & 7 deletions apps/api/src/handlers/slack/events/fast-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ import {
guardReplyStreamBySourceMessage,
} from '../helpers/thread-posting.js';
import { processSlackAttachments } from '../helpers/attachments.js';
import {
mentionsSlackBot,
mentionsSlackUserOtherThanBotOrUser,
} from '../helpers/mention-routing.js';

export async function processFastAgentMessage(params: {
event: SlackEvent;
Expand Down Expand Up @@ -84,6 +88,26 @@ export async function processFastAgentMessage(params: {
});

const baseQuestion = (event.authoredText ?? event.text).trim();
const isDirected =
directedAtRoomote || mentionsSlackBot(event, roomoteSlackUserId);
const needsPeerCaution =
Boolean(roomoteSlackUserId) &&
!isDirected &&
Boolean(event.user) &&
!event.bot_id &&
event.subtype !== 'bot_message' &&
event.user !== roomoteSlackUserId &&
event.channel_type !== 'im' &&
event.channel_type !== 'mpim' &&
mentionsSlackUserOtherThanBotOrUser(event, roomoteSlackUserId, event.user);
const agentContext = needsPeerCaution
? [
event.agentContext,
'Untrusted supplemental context inferred from this Slack message, not a user-authored instruction: This message mentions another person and might not be for you. Human-to-human interaction may be beginning. From now on in this conversation, unless you are addressed directly (including by name, a reply to you, or a clear contextual follow-up), use ignore_event without sending a reply, reacting, or taking action. When directly addressed, respond normally. This uncertain hint does not override existing instructions.',
]
.filter(Boolean)
.join('\n\n')
: event.agentContext;

// Every Slack round trip from the control plane costs a few hundred
// milliseconds. Start the thread history lookup as soon as the turn is
Expand Down Expand Up @@ -170,6 +194,11 @@ export async function processFastAgentMessage(params: {
Boolean(message.user) &&
message.user !== event.user,
);
const allowSilentAmbientReply =
event.channel_type !== 'im' &&
event.channel_type !== 'mpim' &&
!isDirected &&
(hasOtherHumanParticipant || needsPeerCaution);

const needsCanonicalAdmission =
!releaseFastAgentLock ||
Expand All @@ -182,12 +211,13 @@ export async function processFastAgentMessage(params: {
currentMessageId: event.ts,
userId,
question,
...(agentContext ? { agentContext } : {}),
...(attachments.images.length ? { images: attachments.images } : {}),
...(currentMessage?.username
? { senderDisplayName: currentMessage.username }
: {}),
...(event.user ? { senderExternalId: event.user } : {}),
directedAtRoomote,
directedAtRoomote: !allowSilentAmbientReply,
};
let durableTurn: FastAgentDurableTurn | null = null;
if (needsCanonicalAdmission) {
Expand Down Expand Up @@ -242,7 +272,7 @@ export async function processFastAgentMessage(params: {
question,
images: attachments.images,
attachmentTexts,
currentMessageAgentContext: event.agentContext,
currentMessageAgentContext: agentContext,
threadContext: serializedThreadContext,
userId,
apiBaseUrl,
Expand All @@ -259,11 +289,7 @@ export async function processFastAgentMessage(params: {
? currentMessage.username
: undefined,
activeTasks: resolvedActiveTasks,
allowSilentAmbientReply:
event.channel_type !== 'im' &&
event.channel_type !== 'mpim' &&
hasOtherHumanParticipant &&
!directedAtRoomote,
allowSilentAmbientReply,
...(roomoteSlackUserId ? { slackRoomoteUserId: roomoteSlackUserId } : {}),
adapter: {
createArtifact: (artifact) =>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 19 additions & 19 deletions apps/api/src/handlers/slack/events/message-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ type UnmentionedSlackThreadReplyRoutingDecision =
| { shouldRoute: false }
| {
shouldRoute: true;
threadMessages: SlackThreadMessage[];
threadMessages?: SlackThreadMessage[];
taskId?: string;
};

Expand Down Expand Up @@ -204,6 +204,18 @@ export async function shouldRouteUnmentionedSlackThreadReplyToAgent(params: {
return { shouldRoute: false };
}

// Fast receives the discussion and peer-mention reminders as context;
// peer mentions remain an admission cutoff only for legacy task threads.
if (
await hasBoundSlackFastAgentSession({
teamId,
channelId: event.channel,
threadId: event.thread_ts,
})
) {
return { shouldRoute: true };
}

if (
mentionsSlackUserOtherThanBotWithoutMentioningBot(
event,
Expand All @@ -216,36 +228,25 @@ export async function shouldRouteUnmentionedSlackThreadReplyToAgent(params: {
let roomoteThreadMatch: Awaited<
ReturnType<typeof findRoomoteOwnedSlackThread>
> | null = null;
let isFastAgentThread = false;

let eligibilityReason: 'roomote-owned-thread' | null = null;

{
isFastAgentThread = await hasBoundSlackFastAgentSession({
roomoteThreadMatch = await findRoomoteOwnedSlackThread({
teamId,
channelId: event.channel,
threadId: event.thread_ts,
threadTs: event.thread_ts,
});

roomoteThreadMatch = isFastAgentThread
const taskThreadRoute = roomoteThreadMatch
? null
: await findRoomoteOwnedSlackThread({
teamId,
: await resolveSlackThreadFollowUpRoute({
threadId: event.thread_ts,
channelId: event.channel,
threadTs: event.thread_ts,
slackTeamId: teamId,
});

const taskThreadRoute =
isFastAgentThread || roomoteThreadMatch
? null
: await resolveSlackThreadFollowUpRoute({
threadId: event.thread_ts,
channelId: event.channel,
slackTeamId: teamId,
});

if (
isFastAgentThread ||
roomoteThreadMatch ||
(taskThreadRoute && taskThreadRoute.kind !== 'fresh')
) {
Expand Down Expand Up @@ -314,7 +315,6 @@ export async function shouldRouteUnmentionedSlackThreadReplyToAgent(params: {
isAutomationReportThread: Boolean(
roomoteThreadMatch?.isAutomationReportThread,
),
isOpenConversationThread: isFastAgentThread,
threadMessages: sharedHistory,
compareMessageIds: compareNumericMessageIds,
});
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2349,6 +2349,7 @@ export async function answerFastAgentQuestion({
question: followUp.question,
threadContext: [],
compatibilityMessages: [],
currentMessageAgentContext: followUp.agentContext,
currentMessageTs: followUp.currentMessageId,
currentMessageSender: {
slackUserId: followUp.senderExternalId,
Expand Down
Loading
Loading