fix: harden message hook session/group context and add integration coverage (#9859) (thanks @Drickon)

This commit is contained in:
Peter Steinberger
2026-03-02 22:34:27 +00:00
parent b5102ba4f9
commit 29dde80c3e
9 changed files with 310 additions and 46 deletions

View File

@@ -144,12 +144,16 @@ export async function getReplyFromConfig(
finalized.Provider ??
""
).toLowerCase();
const hookSessionKey = finalized.SessionKey?.trim();
const conversationId = finalized.OriginatingTo ?? finalized.To ?? finalized.From ?? undefined;
const isGroupConversation = Boolean(finalized.GroupSubject || finalized.GroupChannel);
const groupId = isGroupConversation ? conversationId : undefined;
// Trigger message:transcribed hook after media understanding completes
// Only fire if transcription actually occurred (skip in fast test mode or non-audio)
if (finalized.Transcript) {
if (!isFastTestEnv && hookSessionKey && finalized.Transcript) {
void triggerInternalHook(
createInternalHookEvent("message", "transcribed", finalized.SessionKey ?? "", {
createInternalHookEvent("message", "transcribed", hookSessionKey, {
from: finalized.From,
to: finalized.To,
body: finalized.Body,
@@ -157,7 +161,7 @@ export async function getReplyFromConfig(
transcript: finalized.Transcript,
timestamp: finalized.Timestamp,
channelId,
conversationId: finalized.OriginatingTo ?? finalized.To ?? finalized.From ?? undefined,
conversationId,
messageId: finalized.MessageSid,
senderId: finalized.SenderId,
senderName: finalized.SenderName,
@@ -176,34 +180,33 @@ export async function getReplyFromConfig(
// Trigger message:preprocessed hook after all media + link understanding.
// Fires for every message, giving hooks access to the fully enriched body
// (transcripts, image descriptions, link summaries) before the agent sees it.
void triggerInternalHook(
createInternalHookEvent("message", "preprocessed", finalized.SessionKey ?? "", {
from: finalized.From,
to: finalized.To,
body: finalized.Body,
bodyForAgent: finalized.BodyForAgent,
transcript: finalized.Transcript,
timestamp: finalized.Timestamp,
channelId,
conversationId: finalized.OriginatingTo ?? finalized.To ?? finalized.From ?? undefined,
messageId: finalized.MessageSid,
senderId: finalized.SenderId,
senderName: finalized.SenderName,
senderUsername: finalized.SenderUsername,
provider: finalized.Provider,
surface: finalized.Surface,
mediaPath: finalized.MediaPath,
mediaType: finalized.MediaType,
isGroup: Boolean(finalized.GroupSubject || finalized.GroupChannel),
groupId:
finalized.From?.includes(":group:") || finalized.From?.includes(":channel:")
? finalized.From
: undefined,
cfg,
}),
).catch((err) => {
logVerbose(`get-reply: message:preprocessed internal hook failed: ${String(err)}`);
});
if (!isFastTestEnv && hookSessionKey) {
void triggerInternalHook(
createInternalHookEvent("message", "preprocessed", hookSessionKey, {
from: finalized.From,
to: finalized.To,
body: finalized.Body,
bodyForAgent: finalized.BodyForAgent,
transcript: finalized.Transcript,
timestamp: finalized.Timestamp,
channelId,
conversationId,
messageId: finalized.MessageSid,
senderId: finalized.SenderId,
senderName: finalized.SenderName,
senderUsername: finalized.SenderUsername,
provider: finalized.Provider,
surface: finalized.Surface,
mediaPath: finalized.MediaPath,
mediaType: finalized.MediaType,
isGroup: isGroupConversation,
groupId,
cfg,
}),
).catch((err) => {
logVerbose(`get-reply: message:preprocessed internal hook failed: ${String(err)}`);
});
}
const commandAuthorized = finalized.CommandAuthorized;
resolveCommandAuthorization({