mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 21:44:32 +00:00
feat(hooks): add message:transcribed and message:preprocessed internal hooks
Adds two new internal hook events that fire after media/link processing:
- message:transcribed: fires when audio has been transcribed, providing
the transcript text alongside the original body and media metadata.
Useful for logging, analytics, or routing based on spoken content.
- message:preprocessed: fires for every message after all media + link
understanding completes. Gives hooks access to the fully enriched body
(transcripts, image descriptions, link summaries) before the agent sees it.
Both hooks are added in get-reply.ts, after applyMediaUnderstanding and
applyLinkUnderstanding. message:received and message:sent are already
in upstream (f07bb8e8) and are not duplicated here.
Typed contexts (MessageTranscribedHookContext, MessagePreprocessedHookContext)
and type guards (isMessageTranscribedEvent, isMessagePreprocessedEvent) added
to internal-hooks.ts alongside the existing received/sent types.
Test coverage in src/hooks/message-hooks.test.ts.
This commit is contained in:
committed by
Peter Steinberger
parent
44183c6eb1
commit
e0b8b80067
@@ -93,6 +93,92 @@ export type MessageSentHookEvent = InternalHookEvent & {
|
||||
context: MessageSentHookContext;
|
||||
};
|
||||
|
||||
export type MessageTranscribedHookContext = {
|
||||
/** Sender identifier (e.g., phone number, user ID) */
|
||||
from?: string;
|
||||
/** Recipient identifier */
|
||||
to?: string;
|
||||
/** Original raw message body (e.g., "🎤 [Audio]") */
|
||||
body?: string;
|
||||
/** Enriched body shown to the agent, including transcript */
|
||||
bodyForAgent?: string;
|
||||
/** The transcribed text from audio */
|
||||
transcript: string;
|
||||
/** Unix timestamp when the message was received */
|
||||
timestamp?: number;
|
||||
/** Channel identifier (e.g., "telegram", "whatsapp") */
|
||||
channelId: string;
|
||||
/** Conversation/chat ID */
|
||||
conversationId?: string;
|
||||
/** Message ID from the provider */
|
||||
messageId?: string;
|
||||
/** Sender user ID */
|
||||
senderId?: string;
|
||||
/** Sender display name */
|
||||
senderName?: string;
|
||||
/** Sender username */
|
||||
senderUsername?: string;
|
||||
/** Provider name */
|
||||
provider?: string;
|
||||
/** Surface name */
|
||||
surface?: string;
|
||||
/** Path to the media file that was transcribed */
|
||||
mediaPath?: string;
|
||||
/** MIME type of the media */
|
||||
mediaType?: string;
|
||||
};
|
||||
|
||||
export type MessageTranscribedHookEvent = InternalHookEvent & {
|
||||
type: "message";
|
||||
action: "transcribed";
|
||||
context: MessageTranscribedHookContext;
|
||||
};
|
||||
|
||||
export type MessagePreprocessedHookContext = {
|
||||
/** Sender identifier (e.g., phone number, user ID) */
|
||||
from?: string;
|
||||
/** Recipient identifier */
|
||||
to?: string;
|
||||
/** Original raw message body */
|
||||
body?: string;
|
||||
/** Fully enriched body shown to the agent (transcripts, image descriptions, link summaries) */
|
||||
bodyForAgent?: string;
|
||||
/** Transcribed audio text, if the message contained audio */
|
||||
transcript?: string;
|
||||
/** Unix timestamp when the message was received */
|
||||
timestamp?: number;
|
||||
/** Channel identifier (e.g., "telegram", "whatsapp") */
|
||||
channelId: string;
|
||||
/** Conversation/chat ID */
|
||||
conversationId?: string;
|
||||
/** Message ID from the provider */
|
||||
messageId?: string;
|
||||
/** Sender user ID */
|
||||
senderId?: string;
|
||||
/** Sender display name */
|
||||
senderName?: string;
|
||||
/** Sender username */
|
||||
senderUsername?: string;
|
||||
/** Provider name */
|
||||
provider?: string;
|
||||
/** Surface name */
|
||||
surface?: string;
|
||||
/** Path to the media file, if present */
|
||||
mediaPath?: string;
|
||||
/** MIME type of the media, if present */
|
||||
mediaType?: string;
|
||||
/** Whether this message was sent in a group/channel context */
|
||||
isGroup?: boolean;
|
||||
/** Group or channel identifier, if applicable */
|
||||
groupId?: string;
|
||||
};
|
||||
|
||||
export type MessagePreprocessedHookEvent = InternalHookEvent & {
|
||||
type: "message";
|
||||
action: "preprocessed";
|
||||
context: MessagePreprocessedHookContext;
|
||||
};
|
||||
|
||||
export interface InternalHookEvent {
|
||||
/** The type of event (command, session, agent, gateway, etc.) */
|
||||
type: InternalHookEventType;
|
||||
@@ -282,3 +368,29 @@ export function isMessageSentEvent(event: InternalHookEvent): event is MessageSe
|
||||
typeof context.success === "boolean"
|
||||
);
|
||||
}
|
||||
|
||||
export function isMessageTranscribedEvent(
|
||||
event: InternalHookEvent,
|
||||
): event is MessageTranscribedHookEvent {
|
||||
if (event.type !== "message" || event.action !== "transcribed") {
|
||||
return false;
|
||||
}
|
||||
const context = event.context as Partial<MessageTranscribedHookContext> | null;
|
||||
if (!context || typeof context !== "object") {
|
||||
return false;
|
||||
}
|
||||
return typeof context.transcript === "string" && typeof context.channelId === "string";
|
||||
}
|
||||
|
||||
export function isMessagePreprocessedEvent(
|
||||
event: InternalHookEvent,
|
||||
): event is MessagePreprocessedHookEvent {
|
||||
if (event.type !== "message" || event.action !== "preprocessed") {
|
||||
return false;
|
||||
}
|
||||
const context = event.context as Partial<MessagePreprocessedHookContext> | null;
|
||||
if (!context || typeof context !== "object") {
|
||||
return false;
|
||||
}
|
||||
return typeof context.channelId === "string";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user