diff --git a/packages/client/src/BaseConversation.ts b/packages/client/src/BaseConversation.ts index 9de90c38e..35f17357d 100644 --- a/packages/client/src/BaseConversation.ts +++ b/packages/client/src/BaseConversation.ts @@ -1,4 +1,5 @@ -import type { Callbacks, Mode, Status, DisconnectionDetails } from "./types.js"; +import type { Callbacks } from "./events.js"; +import type { Mode, Status, DisconnectionDetails } from "./types.js"; import type { BaseConnection, SessionConfig, @@ -35,12 +36,12 @@ export type { Role, Mode, Status, - Callbacks, DisconnectionDetails, MessagePayload, AudioAlignmentEvent, } from "./types.js"; -export { CALLBACK_KEYS } from "./types.js"; +export type { Callbacks, ConversationEventMap } from "./events.js"; +export { CALLBACK_KEYS } from "./events.js"; /** Allows self-hosting the worklets to avoid whitelisting blob: and data: in the CSP script-src */ export type AudioWorkletConfig = { diff --git a/packages/client/src/events.ts b/packages/client/src/events.ts new file mode 100644 index 000000000..3f70b7756 --- /dev/null +++ b/packages/client/src/events.ts @@ -0,0 +1,174 @@ +import type { + AgentChatResponsePartClientEvent, + AgentResponseCorrection, + AgentToolRequestClientEvent, + AgentToolResponseClientEvent, + AsrInitiationMetadataEvent as AsrInitiationMetadataWireEvent, + ClientToolCallClientEvent, + ConversationMetadata, + Interruption, + McpConnectionStatusClientEvent, + McpToolCallClientEvent, +} from "@elevenlabs/types"; +import type { GeneratedEventMap } from "./generated/events.js"; +import type { + AudioAlignmentEvent, + DisconnectionDetails, + MessagePayload, + Mode, + Status, +} from "./types.js"; + +// --------------------------------------------------------------------------- +// Internally handled wire events — hand-written dispatch in BaseConversation +// --------------------------------------------------------------------------- + +type InternalEventMap = { + message: (props: MessagePayload) => void; + audio: (base64Audio: string) => void; + "unhandled-client-tool-call": ( + params: ClientToolCallClientEvent["client_tool_call"] + ) => void; + debug: (props: unknown) => void; +}; + +// --------------------------------------------------------------------------- +// Extra events not in the wire protocol +// --------------------------------------------------------------------------- + +type ExtraEventMap = { + connect: (props: { conversationId: string }) => void; + disconnect: (details: DisconnectionDetails) => void; + error: (message: string, context?: unknown) => void; + "status-change": (prop: { status: Status }) => void; + "mode-change": (prop: { mode: Mode }) => void; + "can-send-feedback-change": (prop: { canSendFeedback: boolean }) => void; + "audio-alignment": (props: AudioAlignmentEvent) => void; +}; + +// --------------------------------------------------------------------------- +// Full event map = generated + internal + extra +// --------------------------------------------------------------------------- + +/** + * Complete event map for conversation instances. + * + * Generated events use raw wire payload shapes, except `vad-score` which + * is transformed to `{ vadScore }` for backward compatibility. + */ +export type ConversationEventMap = Omit & { + "vad-score": (props: { vadScore: number }) => void; +} & InternalEventMap & + ExtraEventMap; + +// --------------------------------------------------------------------------- +// Callbacks — backward-compatible single-callback interface +// --------------------------------------------------------------------------- + +/** + * Shared Callbacks, ensures all callbacks are implemented across all SDKs + */ +export type Callbacks = { + onConnect?: (props: { conversationId: string }) => void; + onDisconnect?: (details: DisconnectionDetails) => void; + onError?: (message: string, context?: unknown) => void; + onMessage?: (props: MessagePayload) => void; + onAudio?: (base64Audio: string) => void; + onModeChange?: (prop: { mode: Mode }) => void; + onStatusChange?: (prop: { status: Status }) => void; + onCanSendFeedbackChange?: (prop: { canSendFeedback: boolean }) => void; + onUnhandledClientToolCall?: ( + params: ClientToolCallClientEvent["client_tool_call"] + ) => void; + onVadScore?: (props: { vadScore: number }) => void; + onMCPToolCall?: (props: McpToolCallClientEvent["mcp_tool_call"]) => void; + onMCPConnectionStatus?: ( + props: McpConnectionStatusClientEvent["mcp_connection_status"] + ) => void; + onAgentToolRequest?: ( + props: AgentToolRequestClientEvent["agent_tool_request"] + ) => void; + onAgentToolResponse?: ( + props: AgentToolResponseClientEvent["agent_tool_response"] + ) => void; + onConversationMetadata?: ( + props: ConversationMetadata["conversation_initiation_metadata_event"] + ) => void; + onAsrInitiationMetadata?: ( + props: AsrInitiationMetadataWireEvent["asr_initiation_metadata_event"] + ) => void; + onInterruption?: (props: Interruption["interruption_event"]) => void; + onAgentResponseCorrection?: ( + props: AgentResponseCorrection["agent_response_correction_event"] + ) => void; + onAgentChatResponsePart?: ( + props: AgentChatResponsePartClientEvent["text_response_part"] + ) => void; + onGuardrailTriggered?: () => void; + onAudioAlignment?: (props: AudioAlignmentEvent) => void; + // internal debug events, not to be used + onDebug?: (props: unknown) => void; +}; + +/** + * Runtime array of all keys in `Callbacks`, kept in sync with the type above. + */ +export const CALLBACK_KEYS = [ + "onConnect", + "onDisconnect", + "onError", + "onMessage", + "onAudio", + "onModeChange", + "onStatusChange", + "onCanSendFeedbackChange", + "onUnhandledClientToolCall", + "onVadScore", + "onMCPToolCall", + "onMCPConnectionStatus", + "onAgentToolRequest", + "onAgentToolResponse", + "onConversationMetadata", + "onAsrInitiationMetadata", + "onInterruption", + "onAgentResponseCorrection", + "onAgentChatResponsePart", + "onAudioAlignment", + "onGuardrailTriggered", + "onDebug", +] as const satisfies readonly (keyof Callbacks)[]; + +// --------------------------------------------------------------------------- +// Callback key ↔ event name mapping +// --------------------------------------------------------------------------- + +/** + * Maps each callback key to its corresponding event name. + * Hand-written because the mapping isn't a simple mechanical transform + * (e.g. `onMCPToolCall` → `mcp-tool-call`, `onConversationMetadata` → + * `conversation-initiation-metadata`). + */ +export const CALLBACK_KEY_TO_EVENT_NAME = { + onConnect: "connect", + onDisconnect: "disconnect", + onError: "error", + onMessage: "message", + onAudio: "audio", + onModeChange: "mode-change", + onStatusChange: "status-change", + onCanSendFeedbackChange: "can-send-feedback-change", + onUnhandledClientToolCall: "unhandled-client-tool-call", + onVadScore: "vad-score", + onMCPToolCall: "mcp-tool-call", + onMCPConnectionStatus: "mcp-connection-status", + onAgentToolRequest: "agent-tool-request", + onAgentToolResponse: "agent-tool-response", + onConversationMetadata: "conversation-initiation-metadata", + onAsrInitiationMetadata: "asr-initiation-metadata", + onInterruption: "interruption", + onAgentResponseCorrection: "agent-response-correction", + onAgentChatResponsePart: "agent-chat-response-part", + onAudioAlignment: "audio-alignment", + onGuardrailTriggered: "guardrail-triggered", + onDebug: "debug", +} as const satisfies Record; diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 7183d1161..fd77f03e9 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -9,6 +9,7 @@ export type { PartialOptions, ClientToolsConfig, Callbacks, + ConversationEventMap, Status, AudioWorkletConfig, MultimodalMessageInput, diff --git a/packages/client/src/types.ts b/packages/client/src/types.ts index 684fdf030..90843cfbc 100644 --- a/packages/client/src/types.ts +++ b/packages/client/src/types.ts @@ -1,16 +1,4 @@ -import type { - AgentChatResponsePartClientEvent, - AgentResponseCorrection, - AgentToolRequestClientEvent, - AgentToolResponseClientEvent, - AsrInitiationMetadataEvent as AsrInitiationMetadataWireEvent, - AudioEventAlignment, - ClientToolCallClientEvent, - ConversationMetadata, - Interruption, - McpConnectionStatusClientEvent, - McpToolCallClientEvent, -} from "@elevenlabs/types"; +import type { AudioEventAlignment } from "@elevenlabs/types"; /** * Role in the conversation @@ -63,76 +51,3 @@ export interface MessagePayload { source: "user" | "ai"; role: Role; } - -/** - * Shared Callbacks, ensures all callbacks are implemented across all SDKs - */ -export type Callbacks = { - onConnect?: (props: { conversationId: string }) => void; - onDisconnect?: (details: DisconnectionDetails) => void; - onError?: (message: string, context?: unknown) => void; - onMessage?: (props: MessagePayload) => void; - onAudio?: (base64Audio: string) => void; - onModeChange?: (prop: { mode: Mode }) => void; - onStatusChange?: (prop: { status: Status }) => void; - onCanSendFeedbackChange?: (prop: { canSendFeedback: boolean }) => void; - onUnhandledClientToolCall?: ( - params: ClientToolCallClientEvent["client_tool_call"] - ) => void; - onVadScore?: (props: { vadScore: number }) => void; - onMCPToolCall?: (props: McpToolCallClientEvent["mcp_tool_call"]) => void; - onMCPConnectionStatus?: ( - props: McpConnectionStatusClientEvent["mcp_connection_status"] - ) => void; - onAgentToolRequest?: ( - props: AgentToolRequestClientEvent["agent_tool_request"] - ) => void; - onAgentToolResponse?: ( - props: AgentToolResponseClientEvent["agent_tool_response"] - ) => void; - onConversationMetadata?: ( - props: ConversationMetadata["conversation_initiation_metadata_event"] - ) => void; - onAsrInitiationMetadata?: ( - props: AsrInitiationMetadataWireEvent["asr_initiation_metadata_event"] - ) => void; - onInterruption?: (props: Interruption["interruption_event"]) => void; - onAgentResponseCorrection?: ( - props: AgentResponseCorrection["agent_response_correction_event"] - ) => void; - onAgentChatResponsePart?: ( - props: AgentChatResponsePartClientEvent["text_response_part"] - ) => void; - onGuardrailTriggered?: () => void; - onAudioAlignment?: (props: AudioAlignmentEvent) => void; - // internal debug events, not to be used - onDebug?: (props: unknown) => void; -}; - -/** - * Runtime array of all keys in `Callbacks`, kept in sync with the type above. - */ -export const CALLBACK_KEYS = [ - "onConnect", - "onDisconnect", - "onError", - "onMessage", - "onAudio", - "onModeChange", - "onStatusChange", - "onCanSendFeedbackChange", - "onUnhandledClientToolCall", - "onVadScore", - "onMCPToolCall", - "onMCPConnectionStatus", - "onAgentToolRequest", - "onAgentToolResponse", - "onConversationMetadata", - "onAsrInitiationMetadata", - "onInterruption", - "onAgentResponseCorrection", - "onAgentChatResponsePart", - "onAudioAlignment", - "onGuardrailTriggered", - "onDebug", -] as const satisfies readonly (keyof Callbacks)[];