fix(plugins): expose inbound message id before dispatch (#112359)

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
Frank Yang
2026-07-30 04:26:28 +08:00
committed by GitHub
parent 1225aa822f
commit 511ecd9dba
6 changed files with 31 additions and 5 deletions

View File

@@ -768,6 +768,9 @@ has visibility-filtered quoted message data: `replyToId`, `replyToIdFull`,
`replyToBody`, `replyToSender`, and `replyToIsQuote`. Prefer these
first-class fields before reading legacy metadata.
`before_dispatch` receives the canonical inbound `messageId` in both its event
and context.
Prefer typed `threadId` and `replyToId` fields before using channel-specific
metadata.

View File

@@ -466,6 +466,7 @@ export async function chooseDispatchRoute(state: PrepareDispatchOperationReadySt
() =>
hookRunner.runBeforeDispatch(
{
messageId: state.hookContext.messageId,
content: state.hookContext.content,
body: state.hookContext.bodyForAgent ?? state.hookContext.body,
channel: state.hookContext.channelId,
@@ -480,6 +481,7 @@ export async function chooseDispatchRoute(state: PrepareDispatchOperationReadySt
timestamp: state.hookContext.timestamp,
},
{
messageId: state.hookContext.messageId,
channelId: state.hookContext.channelId,
accountId: state.hookContext.accountId,
conversationId: state.inboundClaimContext.conversationId,

View File

@@ -148,6 +148,8 @@ describe("before_dispatch hook", () => {
hookMocks.runner.runBeforeDispatch.mockResolvedValue({ handled: true });
const dispatcher = createDispatcher();
const ctx = createHookCtx({
MessageSid: "discord-message-456",
MessageSidFull: " ",
ReplyToId: "discord-reply-123",
ReplyToIdFull: "discord:channel-1:discord-reply-123",
ReplyToBody: "the quoted parent message",
@@ -163,6 +165,7 @@ describe("before_dispatch hook", () => {
) as
| [
{
messageId?: unknown;
replyToId?: unknown;
replyToIdFull?: unknown;
replyToBody?: unknown;
@@ -170,6 +173,7 @@ describe("before_dispatch hook", () => {
replyToIsQuote?: unknown;
},
{
messageId?: unknown;
replyToId?: unknown;
replyToIdFull?: unknown;
replyToBody?: unknown;
@@ -179,6 +183,7 @@ describe("before_dispatch hook", () => {
]
| undefined;
expect(beforeDispatchCall?.[0]).toMatchObject({
messageId: "discord-message-456",
replyToId: "discord-reply-123",
replyToIdFull: "discord:channel-1:discord-reply-123",
replyToBody: "the quoted parent message",
@@ -186,6 +191,7 @@ describe("before_dispatch hook", () => {
replyToIsQuote: true,
});
expect(beforeDispatchCall?.[1]).toMatchObject({
messageId: "discord-message-456",
replyToId: "discord-reply-123",
replyToIdFull: "discord:channel-1:discord-reply-123",
replyToBody: "the quoted parent message",

View File

@@ -132,6 +132,19 @@ describe("message hook mappers", () => {
expect(canonical.guildId).toBe("guild-1");
});
it("normalizes canonical inbound message id precedence", () => {
expect(
deriveInboundMessageHookContext(
makeInboundCtx({ MessageSidFull: "full-message-id", MessageSid: "short-message-id" }),
).messageId,
).toBe("full-message-id");
expect(
deriveInboundMessageHookContext(
makeInboundCtx({ MessageSidFull: " ", MessageSid: "short-message-id" }),
).messageId,
).toBe("short-message-id");
});
it("uses the session key as the Control UI conversation id", () => {
const canonical = deriveInboundMessageHookContext(
makeInboundCtx({

View File

@@ -188,11 +188,11 @@ export function deriveInboundMessageHookContext(
sessionKey: ctx.SessionKey,
agentId: ctx.AgentId,
messageId:
overrides?.messageId ??
ctx.MessageSidFull ??
ctx.MessageSid ??
ctx.MessageSidFirst ??
ctx.MessageSidLast,
normalizeOptionalString(overrides?.messageId) ??
normalizeOptionalString(ctx.MessageSidFull) ??
normalizeOptionalString(ctx.MessageSid) ??
normalizeOptionalString(ctx.MessageSidFirst) ??
normalizeOptionalString(ctx.MessageSidLast),
senderId: ctx.SenderId,
senderName: ctx.SenderName,
senderUsername: ctx.SenderUsername,

View File

@@ -511,6 +511,7 @@ export type PluginHookInboundClaimResult = {
};
export type PluginHookBeforeDispatchEvent = {
messageId?: string;
content: string;
body?: string;
channel?: string;
@@ -526,6 +527,7 @@ export type PluginHookBeforeDispatchEvent = {
};
export type PluginHookBeforeDispatchContext = {
messageId?: string;
channelId?: string;
accountId?: string;
conversationId?: string;