@mastra/voice-aws-nova-sonic 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +383 -0
- package/dist/index.cjs +1539 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1535 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +354 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/auth.d.ts +6 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/errors.d.ts +17 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/utils/errors.ts","../src/utils/auth.ts","../src/index.ts"],"names":["NovaSonicErrorCode","sendDuration","eventKeys"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Type definitions for AWS Nova 2 Sonic voice integration\n */\n\nimport type { AwsCredentialIdentity } from '@smithy/types';\n\n/**\n * Supported AWS regions for Nova 2 Sonic\n */\nexport type NovaSonicRegion = 'us-east-1' | 'us-west-2' | 'ap-northeast-1';\n\n/**\n * Supported language codes for Nova 2 Sonic\n */\nexport type NovaSonicLanguageCode =\n | 'en-US'\n | 'en-GB'\n | 'en-IN'\n | 'en-AU'\n | 'fr-FR'\n | 'it-IT'\n | 'de-DE'\n | 'es-ES'\n | 'pt-BR'\n | 'hi-IN';\n\n\n/**\n * Tool configuration for Nova 2 Sonic\n */\nexport interface NovaSonicToolConfig {\n name: string;\n description: string;\n inputSchema: {\n type: 'object';\n properties: Record<string, any>;\n required?: string[];\n };\n}\n\n/**\n * Voice configuration for Nova 2 Sonic\n * Supports polyglot voices that can speak multiple languages\n */\nexport interface NovaSonicVoiceConfigDetails {\n /** Voice name/identifier (e.g., 'matthew', 'tiffany', 'amy') */\n name?: string;\n /** Language code for the voice */\n languageCode?: NovaSonicLanguageCode;\n /** Gender preference (masculine or feminine) */\n gender?: 'masculine' | 'feminine';\n}\n\n/**\n * Session configuration for Nova 2 Sonic\n */\nexport interface NovaSonicSessionConfig {\n /** Inference configuration parameters */\n inferenceConfiguration?: {\n maxTokens?: number;\n topP?: number;\n temperature?: number;\n topK?: number;\n stopSequences?: string[];\n };\n /** System instructions for the model */\n instructions?: string;\n /** Tools available to the model */\n tools?: NovaSonicToolConfig[];\n /** Voice configuration */\n voice?: string | NovaSonicVoiceConfigDetails;\n /** Enable knowledge grounding with RAG */\n enableKnowledgeGrounding?: boolean;\n /** Knowledge base configuration */\n knowledgeBaseConfig?: {\n knowledgeBaseId?: string;\n dataSourceId?: string;\n };\n /** Turn-taking configuration */\n turnTaking?: {\n /** Voice activity detection sensitivity (deprecated - use turnDetectionConfiguration instead) */\n vadSensitivity?: number;\n /** Silence duration in milliseconds before ending turn */\n silenceDurationMs?: number;\n };\n /** Turn detection configuration for Nova 2 Sonic */\n turnDetectionConfiguration?: {\n /** Endpointing sensitivity: HIGH (fastest, 1.5s pause), MEDIUM (balanced, 1.75s pause), LOW (slowest, 2s pause) */\n endpointingSensitivity?: 'HIGH' | 'MEDIUM' | 'LOW';\n };\n /** Tool choice configuration */\n toolChoice?: 'auto' | 'any' | { tool: { name: string } };\n}\n\n/**\n * Configuration options for NovaSonicVoice\n */\nexport interface NovaSonicVoiceConfig {\n /** AWS region (default: us-east-1) */\n region?: NovaSonicRegion;\n /** AWS credentials (optional, uses default credential chain if not provided) */\n credentials?: AwsCredentialIdentity;\n /** Model ID (default: amazon.nova-2-sonic-v1:0) */\n model?: string;\n /** Voice configuration */\n speaker?: string | NovaSonicVoiceConfigDetails;\n /** Language code */\n languageCode?: NovaSonicLanguageCode;\n /** System instructions */\n instructions?: string;\n /** Tools available to the model */\n tools?: NovaSonicToolConfig[];\n /** Session configuration */\n sessionConfig?: NovaSonicSessionConfig;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Runtime options that can be passed to methods\n */\nexport interface NovaSonicVoiceOptions {\n /** Override the default speaker/voice */\n speaker?: string | NovaSonicVoiceConfigDetails;\n /** Language code for the response */\n languageCode?: NovaSonicLanguageCode;\n}\n\n/**\n * Event types emitted by NovaSonicVoice\n * Extends the base VoiceEventMap with Nova Sonic specific events\n */\nexport interface NovaSonicEventMap {\n /** Audio response stream - compatible with base VoiceEventMap */\n speaker: NodeJS.ReadableStream;\n /** Audio response with additional metadata */\n speaking: { audio?: string; audioData?: Int16Array; sampleRate?: number };\n /** Text response or transcription - compatible with base VoiceEventMap */\n writing: { text: string; role: 'assistant' | 'user'; generationStage?: 'SPECULATIVE' | 'FINAL' };\n /** Error events - compatible with base VoiceEventMap */\n error: { message: string; code?: string; details?: unknown };\n /** Session state changes */\n session: {\n state: 'connecting' | 'connected' | 'disconnected' | 'disconnecting' | 'error';\n config?: Record<string, unknown>;\n };\n /** Tool calls from the model */\n toolCall: { name: string; args: Record<string, any>; id: string };\n /** Voice activity detection events */\n vad: { type: 'start' | 'end'; timestamp: number };\n /** Interrupt events */\n interrupt: { type: 'user' | 'model'; timestamp: number };\n /** Token usage information */\n usage: {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n };\n /** Turn completion event */\n turnComplete: { timestamp: number };\n /** Allow any additional string keys for extensibility */\n [key: string]: unknown;\n}\n\n/**\n * AWS Nova 2 Sonic bidirectional streaming event types\n * Based on AWS Bedrock InvokeModelWithBidirectionalStream API\n */\nexport interface NovaSonicServerEvent {\n /** Content start event */\n contentStart?: {\n role?: 'ASSISTANT' | 'USER';\n additionalModelFields?: string; // JSON string with generationStage, etc.\n };\n /** Text output event */\n textOutput?: {\n content?: string;\n role?: 'ASSISTANT' | 'USER';\n };\n /** Audio output event */\n audioOutput?: {\n content?: string; // Base64 encoded audio\n };\n /** Tool use event */\n toolUse?: {\n toolName?: string;\n toolUseId?: string;\n input?: Record<string, any>;\n };\n /** Content end event */\n contentEnd?: {\n type?: 'TEXT' | 'AUDIO' | 'TOOL';\n stopReason?: string; // e.g., 'END_TURN', 'INTERRUPTED'\n };\n /** Completion end event */\n completionEnd?: {\n stopReason?: string;\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n };\n };\n /** Error event */\n error?: {\n code?: string;\n message?: string;\n };\n}\n\n/**\n * Client event types sent to AWS Nova 2 Sonic\n */\nexport interface NovaSonicClientEvent {\n /** Session start event */\n sessionStart?: {\n inferenceConfiguration?: {\n maxTokens?: number;\n topP?: number;\n temperature?: number;\n topK?: number;\n stopSequences?: string[];\n };\n turnTaking?: {\n vadSensitivity?: number;\n silenceDurationMs?: number;\n };\n turnDetectionConfiguration?: {\n endpointingSensitivity?: 'HIGH' | 'MEDIUM' | 'LOW';\n };\n };\n /** Prompt start event */\n promptStart?: {\n promptName: string;\n textOutputConfiguration?: {\n mediaType?: string;\n };\n audioOutputConfiguration?: {\n mediaType?: string;\n sampleRateHertz?: number;\n sampleSizeBits?: number;\n channelCount?: number;\n voiceId?: string;\n encoding?: string;\n audioType?: string;\n };\n tools?: Array<{\n name: string;\n description: string;\n inputSchema: {\n type: 'object';\n properties: Record<string, any>;\n required?: string[];\n };\n }>;\n toolChoice?: 'auto' | 'any' | { tool: { name: string } };\n knowledgeBaseConfig?: {\n knowledgeBaseId?: string;\n dataSourceId?: string;\n };\n };\n /** Content start event */\n contentStart?: {\n promptName: string;\n contentName: string;\n type: 'TEXT' | 'AUDIO';\n interactive?: boolean;\n role: 'SYSTEM' | 'USER' | 'ASSISTANT';\n textInputConfiguration?: {\n mediaType?: string;\n };\n audioInputConfiguration?: {\n mediaType?: string;\n sampleRateHertz?: number;\n sampleSizeBits?: number;\n channelCount?: number;\n encoding?: string;\n audioType?: string;\n };\n };\n /** Text input event */\n textInput?: {\n promptName: string;\n contentName: string;\n content: string;\n };\n /** Content end event */\n contentEnd?: {\n promptName: string;\n contentName: string;\n };\n /** Prompt end event */\n promptEnd?: {\n promptName: string;\n };\n /** Session end event */\n sessionEnd?: Record<string, unknown>;\n /** Audio input event (for streaming audio chunks) */\n audioInput?: {\n promptName: string;\n contentName: string;\n content: string; // Base64 encoded audio\n };\n /** Tool result */\n toolResult?: {\n toolUseId?: string;\n content?: Array<{\n text?: string;\n json?: Record<string, any>;\n }>;\n };\n /** Tool start */\n toolStart?: {\n toolUseId?: string;\n };\n /** Tool content end */\n toolContentEnd?: {\n toolUseId?: string;\n };\n}\n\n/**\n * Error codes for Nova Sonic specific errors\n */\nexport enum NovaSonicErrorCode {\n CONNECTION_FAILED = 'connection_failed',\n CONNECTION_NOT_ESTABLISHED = 'connection_not_established',\n AUTHENTICATION_FAILED = 'authentication_failed',\n CREDENTIALS_MISSING = 'credentials_missing',\n REGION_INVALID = 'region_invalid',\n WEBSOCKET_ERROR = 'websocket_error',\n AUDIO_PROCESSING_ERROR = 'audio_processing_error',\n AUDIO_STREAM_ERROR = 'audio_stream_error',\n SPEAKER_STREAM_ERROR = 'speaker_stream_error',\n TRANSCRIPTION_TIMEOUT = 'transcription_timeout',\n TRANSCRIPTION_FAILED = 'transcription_failed',\n TOOL_EXECUTION_ERROR = 'tool_execution_error',\n TOOL_NOT_FOUND = 'tool_not_found',\n SESSION_CONFIG_UPDATE_FAILED = 'session_config_update_failed',\n INVALID_AUDIO_FORMAT = 'invalid_audio_format',\n NOT_CONNECTED = 'not_connected',\n INVALID_STATE = 'invalid_state',\n VALIDATION_ERROR = 'validation_error',\n UNKNOWN_ERROR = 'unknown_error',\n}\n\n","import type { NovaSonicErrorCode } from '../types';\n\n/**\n * Helper class for consistent error handling across Nova Sonic voice integration\n */\nexport class NovaSonicError extends Error {\n public readonly code: string;\n public readonly details?: unknown;\n public readonly timestamp: number;\n\n constructor(code: NovaSonicErrorCode | string, message: string, details?: unknown) {\n super(message);\n this.name = 'NovaSonicError';\n this.code = code;\n this.details = details;\n this.timestamp = Date.now();\n }\n\n toEventData() {\n return {\n message: this.message,\n code: this.code,\n details: this.details,\n timestamp: this.timestamp,\n };\n }\n}\n\n","import type { AwsCredentialIdentity } from '@smithy/types';\nimport { defaultProvider } from '@aws-sdk/credential-provider-node';\nimport { NovaSonicError } from './errors';\nimport { NovaSonicErrorCode } from '../types';\n\n/**\n * Get AWS credentials from various sources\n */\nexport async function getAwsCredentials(\n explicitCredentials?: AwsCredentialIdentity,\n debug?: boolean,\n): Promise<AwsCredentialIdentity> {\n if (explicitCredentials) {\n if (debug) {\n console.log('[getAwsCredentials] Using explicit credentials provided in config');\n }\n return explicitCredentials;\n }\n\n // Use default credential provider chain\n // This will check:\n // 1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)\n // 2. Shared credentials file (~/.aws/credentials)\n // 3. IAM roles (for EC2/Lambda)\n // 4. ECS task roles\n // 5. Other credential sources\n try {\n if (debug) {\n console.log('[getAwsCredentials] Using default credential provider chain');\n }\n\n const credentials = await defaultProvider()();\n\n if (debug) {\n console.log('[getAwsCredentials] Credentials retrieved successfully');\n }\n\n return credentials;\n } catch (error) {\n if (error instanceof NovaSonicError) {\n throw error;\n }\n throw new NovaSonicError(\n NovaSonicErrorCode.AUTHENTICATION_FAILED,\n `Failed to load AWS credentials: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error,\n );\n }\n}\n\n","import { PassThrough } from 'node:stream';\nimport { randomUUID } from 'node:crypto';\nimport type { ToolsInput } from '@mastra/core/agent';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { MastraVoice } from '@mastra/core/voice';\nimport type { VoiceConfig, VoiceEventType } from '@mastra/core/voice';\nimport {\n BedrockRuntimeClient,\n InvokeModelWithBidirectionalStreamCommand,\n} from '@aws-sdk/client-bedrock-runtime';\nimport {\n NodeHttp2Handler,\n} from '@smithy/node-http-handler';\n\nimport type { AwsCredentialIdentity } from '@smithy/types';\nimport type {\n NovaSonicVoiceConfig as ConfigType,\n NovaSonicVoiceOptions,\n NovaSonicEventMap,\n NovaSonicServerEvent,\n NovaSonicClientEvent,\n NovaSonicRegion,\n} from './types';\nimport { NovaSonicErrorCode as ErrorCode } from './types';\nimport { NovaSonicError } from './utils/errors';\n\n// Re-export for consumer usage (error handling, type checking)\nexport { NovaSonicError } from './utils/errors';\nexport { NovaSonicErrorCode } from './types';\nexport type { NovaSonicVoiceConfig, NovaSonicSessionConfig, NovaSonicToolConfig, NovaSonicVoiceOptions } from './types';\nimport { getAwsCredentials } from './utils/auth';\n\n/**\n * Default configuration values\n */\nconst DEFAULT_MODEL = 'amazon.nova-2-sonic-v1:0';\nconst DEFAULT_REGION: NovaSonicRegion = 'us-east-1';\n\n/**\n * Event callback function type\n */\ntype EventCallback = (...args: any[]) => void;\n\ntype StreamWithId = PassThrough & { id: string };\n\n/**\n * Map of event types to their callback arrays\n */\ntype EventMap = Record<string, EventCallback[]>;\n\n/**\n * NovaSonicVoice provides real-time voice interaction capabilities using AWS Nova 2 Sonic's\n * bidirectional streaming API. It supports:\n * - Real-time text-to-speech\n * - Speech-to-text (transcription)\n * - Voice activity detection\n * - Multiple voice options and languages\n * - Polyglot voices\n * - Tool/function calling\n * - Cross-modal input (audio and text)\n *\n * The class manages HTTP/2 bidirectional streaming connections, audio streaming, and event handling\n * for seamless voice interactions.\n *\n * @extends MastraVoice\n *\n * @example\n * ```typescript\n * const voice = new NovaSonicVoice({\n * region: 'us-east-1',\n * model: 'amazon.nova-2-sonic-v1:0',\n * speaker: 'default',\n * });\n *\n * await voice.connect();\n * voice.on('speaking', ({ audio }) => {\n * // Handle audio data\n * });\n *\n * await voice.speak('Hello, how can I help you today?');\n * ```\n */\nexport class NovaSonicVoice extends MastraVoice<\n ConfigType,\n NovaSonicVoiceOptions,\n NovaSonicVoiceOptions,\n ToolsInput,\n NovaSonicEventMap\n> {\n private client?: BedrockRuntimeClient;\n private stream?: AsyncIterable<any>;\n private inputStream?: PassThrough; // Input stream for sending events to AWS\n private _eventQueue?: Array<{ event: any }>;\n private _signalQueue?: () => void;\n private _closeSignal?: () => void;\n private _promptName?: string;\n private state: 'disconnected' | 'connecting' | 'connected' = 'disconnected';\n private events: EventMap;\n private instructions?: string;\n private tools?: ToolsInput;\n private requestContext?: RequestContext;\n private debug: boolean;\n private region: NovaSonicRegion;\n private model: string;\n private credentials?: AwsCredentialIdentity;\n private speakerStreams: Map<string, StreamWithId>;\n private currentResponseId?: string;\n private processingStream = false;\n private streamRestartAttempted = false; // Prevent multiple restart attempts\n private sessionConfig?: ConfigType['sessionConfig'];\n private promptStarted = false; // Track if promptStart was sent (now sent during connection)\n private audioContentName?: string;\n private audioContentStarted = false;\n private hasSentContentEnd = false; // Track if contentEnd has been sent for current turn\n private turnCompleted = false; // Track if turn has been completed (to prevent sending contentEnd after turn completion)\n private turnCompleteTimeout?: NodeJS.Timeout; // Timeout for fallback turn completion\n private isReceivingAssistantAudio = false; // Track if we're currently receiving assistant audio output\n private currentTextGenerationStage?: string; // Track generationStage (SPECULATIVE|FINAL) for current text content block\n\n /**\n * Creates a new instance of NovaSonicVoice.\n *\n * @param config - Configuration options for the voice instance\n * @param config.region - AWS region (defaults to us-east-1)\n * @param config.model - The model ID to use (defaults to amazon.nova-2-sonic-v1:0)\n * @param config.credentials - AWS credentials (optional, uses default credential chain)\n * @param config.speaker - Voice name/identifier\n * @param config.languageCode - Language code for the voice\n * @param config.debug - Enable debug mode\n *\n * @example\n * ```typescript\n * const voice = new NovaSonicVoice({\n * region: 'us-east-1',\n * model: 'amazon.nova-2-sonic-v1:0',\n * speaker: 'default',\n * });\n * ```\n */\n constructor(\n config: VoiceConfig<ConfigType> | ConfigType = {},\n ) {\n // Normalize config to VoiceConfig format\n let normalizedConfig: VoiceConfig<ConfigType>;\n if ('realtimeConfig' in config || 'speechModel' in config || 'listeningModel' in config) {\n normalizedConfig = config as VoiceConfig<ConfigType>;\n } else {\n const configOptions = config as ConfigType;\n normalizedConfig = {\n realtimeConfig: {\n model: configOptions.model || DEFAULT_MODEL,\n apiKey: undefined, // AWS doesn't use API keys\n options: configOptions,\n },\n speaker: typeof configOptions.speaker === 'string' ? configOptions.speaker : 'matthew',\n };\n }\n\n super(normalizedConfig);\n\n const options = normalizedConfig.realtimeConfig?.options || (config as ConfigType);\n this.region = (options.region as NovaSonicRegion) || DEFAULT_REGION;\n this.model = options.model || DEFAULT_MODEL;\n this.credentials = options.credentials;\n this.debug = options.debug || false;\n this.sessionConfig = options.sessionConfig;\n // Speaker is set by parent class constructor\n this.events = {} as EventMap;\n this.speakerStreams = new Map();\n\n // Validate region\n const validRegions: NovaSonicRegion[] = ['us-east-1', 'us-west-2', 'ap-northeast-1'];\n if (!validRegions.includes(this.region)) {\n throw new NovaSonicError(\n ErrorCode.REGION_INVALID,\n `Invalid region: ${this.region}. Supported regions: ${validRegions.join(', ')}`,\n );\n }\n }\n\n /**\n * Returns a list of available voice speakers.\n * \n * Nova 2 Sonic provides expressive voices across multiple languages.\n * Tiffany (en-US, feminine) and Matthew (en-US, masculine) are polyglot\n * voices that can speak all supported languages.\n *\n * @returns Promise resolving to an array of voice objects\n */\n async getSpeakers(): Promise<Array<{ voiceId: string; name: string; language: string; locale: string; gender: 'masculine' | 'feminine'; polyglot: boolean }>> {\n // Nova 2 Sonic available voices according to AWS documentation\n return Promise.resolve([\n // English (US) - Polyglot voices\n { voiceId: 'tiffany', name: 'Tiffany', language: 'English', locale: 'en-US', gender: 'feminine', polyglot: true },\n { voiceId: 'matthew', name: 'Matthew', language: 'English', locale: 'en-US', gender: 'masculine', polyglot: true },\n // English (UK)\n { voiceId: 'amy', name: 'Amy', language: 'English', locale: 'en-GB', gender: 'feminine', polyglot: false },\n // English (Australia)\n { voiceId: 'olivia', name: 'Olivia', language: 'English', locale: 'en-AU', gender: 'feminine', polyglot: false },\n // English (Indian)\n { voiceId: 'kiara', name: 'Kiara', language: 'English', locale: 'en-IN', gender: 'feminine', polyglot: false },\n { voiceId: 'arjun', name: 'Arjun', language: 'English', locale: 'en-IN', gender: 'masculine', polyglot: false },\n // French\n { voiceId: 'ambre', name: 'Ambre', language: 'French', locale: 'fr-FR', gender: 'feminine', polyglot: false },\n { voiceId: 'florian', name: 'Florian', language: 'French', locale: 'fr-FR', gender: 'masculine', polyglot: false },\n // Italian\n { voiceId: 'beatrice', name: 'Beatrice', language: 'Italian', locale: 'it-IT', gender: 'feminine', polyglot: false },\n { voiceId: 'lorenzo', name: 'Lorenzo', language: 'Italian', locale: 'it-IT', gender: 'masculine', polyglot: false },\n // German\n { voiceId: 'tina', name: 'Tina', language: 'German', locale: 'de-DE', gender: 'feminine', polyglot: false },\n { voiceId: 'lennart', name: 'Lennart', language: 'German', locale: 'de-DE', gender: 'masculine', polyglot: false },\n // Spanish (US)\n { voiceId: 'lupe', name: 'Lupe', language: 'Spanish', locale: 'es-US', gender: 'feminine', polyglot: false },\n { voiceId: 'carlos', name: 'Carlos', language: 'Spanish', locale: 'es-US', gender: 'masculine', polyglot: false },\n // Portuguese\n { voiceId: 'carolina', name: 'Carolina', language: 'Portuguese', locale: 'pt-BR', gender: 'feminine', polyglot: false },\n { voiceId: 'leo', name: 'Leo', language: 'Portuguese', locale: 'pt-BR', gender: 'masculine', polyglot: false },\n // Hindi\n { voiceId: 'kiara', name: 'Kiara', language: 'Hindi', locale: 'hi-IN', gender: 'feminine', polyglot: false },\n { voiceId: 'arjun', name: 'Arjun', language: 'Hindi', locale: 'hi-IN', gender: 'masculine', polyglot: false },\n ]);\n }\n\n /**\n * Establishes a connection to the AWS Bedrock bidirectional streaming service.\n * Must be called before using speak, listen, or send functions.\n *\n * @throws {NovaSonicError} If connection fails or credentials are missing\n *\n * @example\n * ```typescript\n * await voice.connect();\n * // Now ready for voice interactions\n * ```\n */\n async connect({ requestContext }: { requestContext?: RequestContext } = {}): Promise<void> {\n if (this.state === 'connected' || this.state === 'connecting') {\n this.log('Already connected or connecting');\n return;\n }\n\n this.state = 'connecting';\n this.requestContext = requestContext;\n this.streamRestartAttempted = false;\n\n try {\n await this.createBedrockClient();\n const asyncIterable = this.createEventQueue();\n this.enqueueInitialSessionEvents();\n await this.sendInitialConnectCommand(asyncIterable);\n\n // Start processing the stream (fire and forget)\n this.processStream().catch((error) => {\n this.log('Error in stream processing:', error);\n this.emit('error', {\n message: error instanceof Error ? error.message : 'Stream processing error',\n code: 'STREAM_PROCESSING_ERROR',\n details: error,\n });\n });\n\n this.log('Connected to AWS Bedrock Nova 2 Sonic');\n } catch (error) {\n this.state = 'disconnected';\n if (this.client) {\n if (typeof this.client.destroy === 'function') {\n this.client.destroy();\n }\n this.client = undefined;\n }\n this.log('Connection error:', error);\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error during connection';\n throw new NovaSonicError(\n ErrorCode.CONNECTION_FAILED,\n `Failed to connect to AWS Bedrock: ${errorMessage}`,\n error,\n );\n }\n }\n\n /**\n * Resolve credentials and initialize the Bedrock Runtime client over HTTP/2.\n */\n private async createBedrockClient(): Promise<void> {\n this.log('Getting AWS credentials...');\n const credentials = await getAwsCredentials(this.credentials, this.debug);\n\n if (!credentials) {\n throw new NovaSonicError(\n ErrorCode.CREDENTIALS_MISSING,\n 'AWS credentials are required. Please configure AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables or provide credentials in the config.',\n );\n }\n\n // Log credentials info (masked for security)\n this.log('Credentials retrieved:', {\n hasAccessKeyId: !!credentials.accessKeyId,\n hasSecretAccessKey: !!credentials.secretAccessKey,\n hasSessionToken: !!credentials.sessionToken,\n accessKeyIdPrefix: credentials.accessKeyId ? `${credentials.accessKeyId.substring(0, 6)}...` : 'missing',\n expiration: credentials.expiration ? credentials.expiration.toISOString() : 'no expiration',\n });\n\n this.log(`Initializing Bedrock Runtime client for region: ${this.region}, model: ${this.model}`);\n\n // Use NodeHttp2Handler for bidirectional streaming\n const nodeHttp2Handler = new NodeHttp2Handler({\n requestTimeout: 300000, // 5 minutes\n sessionTimeout: 300000, // 5 minutes\n disableConcurrentStreams: false,\n maxConcurrentStreams: 20,\n });\n\n this.client = new BedrockRuntimeClient({\n region: this.region,\n credentials,\n requestHandler: nodeHttp2Handler,\n });\n }\n\n /**\n * Build the async-iterable event queue used as the request body for the\n * bidirectional stream. Returns the iterable and wires up internal queue\n * helpers (_eventQueue, _signalQueue, _closeSignal) used by sendClientEvent.\n */\n private createEventQueue(): AsyncIterable<any> {\n this.log('Creating bidirectional stream command...');\n \n // Use a queue to store events and a signal to wake up the iterator\n // The iterator waits on the signal when queue is empty, allowing SDK to establish connection\n // Use array of resolve functions to handle multiple concurrent next() calls\n const voiceInstance = this;\n const eventQueue: Array<{ event: any }> = [];\n const pendingResolvers: Array<() => void> = [];\n let closeSignal = false;\n let streamError: Error | null = null;\n \n // Function to signal that data is available in the queue\n // Resolves all pending Promises (handles multiple concurrent next() calls)\n const signalQueue = () => {\n if (pendingResolvers.length > 0) {\n voiceInstance.log(`[AsyncIterable] Signaling queue - resolving ${pendingResolvers.length} pending Promise(s)`);\n const resolvers = [...pendingResolvers];\n pendingResolvers.length = 0; // Clear array\n resolvers.forEach(resolve => resolve());\n } else {\n voiceInstance.log('[AsyncIterable] signalQueue called but no pending Promise');\n }\n };\n \n // Create async iterable\n const asyncIterable = {\n [Symbol.asyncIterator]: () => {\n voiceInstance.log('[AsyncIterable] Iterator requested');\n \n return {\n next: async (): Promise<IteratorResult<any>> => {\n try {\n // Check if closed\n // Allow 'connecting' state since iterator is created during connection\n if (closeSignal || voiceInstance.state === 'disconnected') {\n voiceInstance.log(`[AsyncIterable] Stream closed (state: ${voiceInstance.state}), done = true`);\n return { value: undefined, done: true };\n }\n \n // Wait for items in the queue or close signal\n // CRITICAL: We must wait indefinitely when queue is empty, as long as connection is active\n // Only return done: true when explicitly closed or disconnected\n // This keeps the stream open for ongoing conversation\n if (eventQueue.length === 0) {\n try {\n voiceInstance.log('[AsyncIterable] Queue empty, waiting for signal...');\n // Wait for signal that data is available or stream is closed\n // This Promise stays pending until signalQueue() is called OR connection is closed\n // We DON'T timeout here - we wait indefinitely for new events as long as connection is active\n await new Promise<void>((resolve) => {\n // Add to array of pending resolvers (handles multiple concurrent next() calls)\n pendingResolvers.push(resolve);\n voiceInstance.log(`[AsyncIterable] Promise created, waiting for signal (${pendingResolvers.length} pending)...`);\n \n // Double-check conditions after setting up the resolve\n setImmediate(() => {\n // If data arrived or connection closed, resolve immediately\n if (eventQueue.length > 0) {\n voiceInstance.log('[AsyncIterable] Data arrived before wait, resolving immediately');\n const index = pendingResolvers.indexOf(resolve);\n if (index !== -1) {\n pendingResolvers.splice(index, 1);\n resolve();\n }\n return;\n }\n if (closeSignal || voiceInstance.state === 'disconnected') {\n voiceInstance.log('[AsyncIterable] Closed before wait, resolving');\n const index = pendingResolvers.indexOf(resolve);\n if (index !== -1) {\n pendingResolvers.splice(index, 1);\n resolve();\n }\n return;\n }\n // Otherwise, Promise stays pending until signalQueue() is called\n // This allows SDK to establish connection while waiting\n // We DON'T timeout here - we wait indefinitely for new events\n });\n });\n voiceInstance.log('[AsyncIterable] Promise resolved, checking queue...');\n } catch (error) {\n if (error instanceof Error && error.message === 'Stream closed') {\n voiceInstance.log('[AsyncIterable] Stream closed during wait');\n return { value: undefined, done: true };\n }\n voiceInstance.log('[AsyncIterable] Error during wait:', error);\n }\n }\n \n // Check if closed after waiting (state could have changed)\n if (closeSignal) {\n voiceInstance.log('[AsyncIterable] Stream closed (closeSignal)');\n return { value: undefined, done: true };\n }\n // Check state (use type assertion to avoid TypeScript narrowing issues)\n if ((voiceInstance.state as string) === 'disconnected') {\n voiceInstance.log('[AsyncIterable] Stream closed (disconnected state)');\n return { value: undefined, done: true };\n }\n \n // If queue is still empty after signal but connection is still active,\n // we should wait again (not return done: true)\n // This keeps the stream open for ongoing conversation\n // Loop back to wait again if queue is still empty\n while (eventQueue.length === 0 && !closeSignal) {\n // Check state before waiting (use type assertion to avoid narrowing)\n if ((voiceInstance.state as string) === 'disconnected') {\n voiceInstance.log('[AsyncIterable] Stream closed before wait loop');\n return { value: undefined, done: true };\n }\n \n voiceInstance.log('[AsyncIterable] Queue still empty, waiting again...');\n await new Promise<void>((resolve) => {\n pendingResolvers.push(resolve);\n setImmediate(() => {\n // Check state (use type assertion to avoid narrowing)\n if (eventQueue.length > 0 || closeSignal || (voiceInstance.state as string) === 'disconnected') {\n const index = pendingResolvers.indexOf(resolve);\n if (index !== -1) {\n pendingResolvers.splice(index, 1);\n resolve();\n }\n }\n });\n });\n \n // Check if closed after waiting (use type assertion to avoid narrowing)\n if (closeSignal || (voiceInstance.state as string) === 'disconnected') {\n voiceInstance.log('[AsyncIterable] Stream closed during wait loop');\n return { value: undefined, done: true };\n }\n }\n \n // Get next item from queue\n const nextEvent = eventQueue.shift()!;\n const eventJson = JSON.stringify(nextEvent);\n const eventBytes = Buffer.from(eventJson, 'utf-8');\n \n voiceInstance.log(`[AsyncIterable] Yielding event of size: ${eventBytes.length}`);\n return {\n value: {\n chunk: {\n bytes: eventBytes\n }\n },\n done: false\n };\n } catch (error) {\n voiceInstance.log('[AsyncIterable] Error in iterator:', error);\n closeSignal = true;\n return { value: undefined, done: true };\n }\n },\n \n return: async (): Promise<IteratorResult<any>> => {\n voiceInstance.log('[AsyncIterable] Iterator return() called');\n closeSignal = true;\n signalQueue();\n return { value: undefined, done: true };\n },\n \n throw: async (error: any): Promise<IteratorResult<any>> => {\n voiceInstance.log('[AsyncIterable] Iterator throw() called:', error);\n closeSignal = true;\n streamError = error instanceof Error ? error : new Error(String(error));\n signalQueue();\n throw error;\n }\n };\n }\n };\n \n // Store the queue and signal function for use in sendClientEvent\n this._eventQueue = eventQueue;\n this._signalQueue = signalQueue;\n this._closeSignal = () => { closeSignal = true; signalQueue(); };\n\n // Reference streamError to keep it observable for future error propagation\n void streamError;\n\n return asyncIterable;\n }\n\n /**\n * Pre-populate the event queue with the AWS Nova Sonic connection\n * handshake events: sessionStart, promptStart, then a SYSTEM text content\n * block carrying the configured instructions. AUDIO contentStart is NOT\n * sent here; it is deferred to the first send() call.\n */\n private enqueueInitialSessionEvents(): void {\n const eventQueue = this._eventQueue;\n if (!eventQueue) {\n throw new NovaSonicError(\n ErrorCode.CONNECTION_FAILED,\n 'Event queue must be initialized before enqueueing session events',\n );\n }\n\n // CRITICAL: Pre-populate queue with sessionStart and promptStart events BEFORE calling send()\n // AWS requires both sessionStart and promptStart in the initial connection sequence\n this.log('Pre-populating queue with sessionStart and promptStart events...');\n\n // Generate promptName for this session\n const promptName = randomUUID();\n this._promptName = promptName;\n \n // 1. Session start event\n // Build sessionStart event with all available parameters from sessionConfig\n const sessionStartEvent: any = {};\n \n if (this.sessionConfig) {\n // Extract inferenceConfiguration from sessionConfig\n if (this.sessionConfig.inferenceConfiguration) {\n sessionStartEvent.inferenceConfiguration = {\n maxTokens: this.sessionConfig.inferenceConfiguration.maxTokens || 4096,\n topP: this.sessionConfig.inferenceConfiguration.topP || 0.9,\n temperature: this.sessionConfig.inferenceConfiguration.temperature || 0.7,\n ...(this.sessionConfig.inferenceConfiguration.topK !== undefined && { topK: this.sessionConfig.inferenceConfiguration.topK }),\n ...(this.sessionConfig.inferenceConfiguration.stopSequences && { stopSequences: this.sessionConfig.inferenceConfiguration.stopSequences }),\n };\n } else {\n // Default inference configuration if not provided\n sessionStartEvent.inferenceConfiguration = {\n maxTokens: 4096,\n topP: 0.9,\n temperature: 0.7,\n };\n }\n \n // Extract turnDetectionConfiguration (Nova 2 Sonic uses this instead of turnTaking)\n if (this.sessionConfig.turnDetectionConfiguration) {\n sessionStartEvent.turnDetectionConfiguration = {\n ...(this.sessionConfig.turnDetectionConfiguration.endpointingSensitivity && { \n endpointingSensitivity: this.sessionConfig.turnDetectionConfiguration.endpointingSensitivity \n }),\n };\n }\n \n // Note: turnTaking is NOT supported in Nova 2 Sonic - only turnDetectionConfiguration is valid\n // Legacy turnTaking support removed for Nova 2 Sonic compatibility\n } else {\n // Default inference configuration if no sessionConfig provided\n sessionStartEvent.inferenceConfiguration = {\n maxTokens: 4096,\n topP: 0.9,\n temperature: 0.7,\n };\n }\n \n eventQueue.push({\n event: {\n sessionStart: sessionStartEvent,\n },\n });\n \n // 2. Prompt start event (required - AWS validates this during connection)\n // Determine voice ID - prioritize sessionConfig.voice, then this.speaker, then default to matthew\n let voiceId = 'matthew'; // Default polyglot voice\n if (this.sessionConfig?.voice) {\n if (typeof this.sessionConfig.voice === 'string') {\n voiceId = this.sessionConfig.voice;\n } else if (this.sessionConfig.voice.name) {\n voiceId = this.sessionConfig.voice.name;\n }\n } else if (this.speaker && this.speaker !== 'default') {\n if (typeof this.speaker === 'string') {\n voiceId = this.speaker;\n } else {\n // Type guard for object with name property\n const speakerObj = this.speaker as { name?: string };\n if (speakerObj && typeof speakerObj === 'object' && speakerObj.name) {\n voiceId = speakerObj.name;\n }\n }\n }\n \n // Build promptStart event with all available parameters\n // AWS REQUIRES audioOutputConfiguration to be set (it's mandatory)\n // However, when it's set, AWS expects audio input\n // For text-only input, we'll send an empty audio contentEnd to satisfy the requirement\n const promptStartEvent: any = {\n promptName,\n textOutputConfiguration: {\n mediaType: \"text/plain\",\n },\n // AWS REQUIRES this - cannot be omitted\n audioOutputConfiguration: {\n mediaType: \"audio/lpcm\",\n sampleRateHertz: 24000,\n sampleSizeBits: 16,\n channelCount: 1,\n voiceId: voiceId,\n encoding: \"base64\",\n audioType: \"SPEECH\",\n },\n };\n \n // Add toolConfiguration if tools are configured\n // According to AWS Nova 2 Sonic docs, tools should be in toolConfiguration.tools[].toolSpec format\n if (this.sessionConfig?.tools && this.sessionConfig.tools.length > 0) {\n promptStartEvent.toolConfiguration = {\n tools: this.sessionConfig.tools.map(tool => {\n // inputSchema should be a JSON string according to Nova 2 Sonic documentation\n // If it's already a string, use it; otherwise stringify the object\n let inputSchemaJson: string;\n if (typeof tool.inputSchema === 'string') {\n inputSchemaJson = tool.inputSchema;\n } else {\n inputSchemaJson = JSON.stringify(tool.inputSchema);\n }\n \n return {\n toolSpec: {\n name: tool.name,\n description: tool.description,\n inputSchema: {\n json: inputSchemaJson,\n },\n },\n };\n }),\n // toolChoice goes inside toolConfiguration for Nova 2 Sonic\n ...(this.sessionConfig?.toolChoice && { toolChoice: this.sessionConfig.toolChoice }),\n };\n } else if (this.sessionConfig?.toolChoice) {\n // If toolChoice is specified without tools, still include it in toolConfiguration\n promptStartEvent.toolConfiguration = {\n toolChoice: this.sessionConfig.toolChoice,\n };\n }\n \n // Note: knowledgeBaseConfig is not documented in Nova 2 Sonic promptStart event structure\n // If needed, it may be configured differently or may not be supported in the bidirectional streaming API\n // Commenting out for now to ensure compatibility\n // if (this.sessionConfig?.knowledgeBaseConfig) {\n // promptStartEvent.knowledgeBaseConfig = {\n // ...(this.sessionConfig.knowledgeBaseConfig.knowledgeBaseId && { \n // knowledgeBaseId: this.sessionConfig.knowledgeBaseConfig.knowledgeBaseId \n // }),\n // ...(this.sessionConfig.knowledgeBaseConfig.dataSourceId && { \n // dataSourceId: this.sessionConfig.knowledgeBaseConfig.dataSourceId \n // }),\n // };\n // }\n \n eventQueue.push({\n event: {\n promptStart: promptStartEvent,\n },\n });\n \n // Mark prompt as started since we've sent promptStart during connection\n this.promptStarted = true;\n \n // 3. System prompt events\n // AWS requires that the FIRST content after promptStart must have SYSTEM role\n // We always send a SYSTEM content, even if instructions are empty\n const systemContentName = randomUUID();\n // Content start\n eventQueue.push({\n event: {\n contentStart: {\n promptName,\n contentName: systemContentName,\n type: \"TEXT\",\n interactive: false,\n role: \"SYSTEM\",\n textInputConfiguration: {\n mediaType: \"text/plain\",\n },\n },\n },\n });\n // Text input (send instructions if provided, otherwise empty string)\n eventQueue.push({\n event: {\n textInput: {\n promptName,\n contentName: systemContentName,\n content: this.instructions || '',\n },\n },\n });\n // Content end\n eventQueue.push({\n event: {\n contentEnd: {\n promptName,\n contentName: systemContentName,\n },\n },\n });\n \n // 4. Do NOT send AUDIO contentStart during connection\n // AUDIO contentStart should only be sent when audio streaming actually starts (via send() method)\n // The audioContentName will be set when send() is first called\n // This prevents AWS from waiting for audio bytes during connection\n this.audioContentStarted = false;\n\n this.log(`Queue pre-populated with ${eventQueue.length} event(s)`);\n }\n\n /**\n * Issue the InvokeModelWithBidirectionalStreamCommand to AWS Bedrock with\n * a 5-second abort timeout that tears down the client on hang to avoid\n * leaked HTTP/2 sessions. On success the response stream is stored and the\n * voice transitions to 'connected'.\n */\n private async sendInitialConnectCommand(asyncIterable: AsyncIterable<any>): Promise<void> {\n if (!this.client) {\n throw new NovaSonicError(\n ErrorCode.CONNECTION_FAILED,\n 'Bedrock client must be created before sending the initial command',\n );\n }\n\n // According to AWS docs, body is optional for bidirectional streaming, but\n // the SDK requires it - we provide an async iterable that yields when data is available.\n const command = new InvokeModelWithBidirectionalStreamCommand({\n modelId: this.model,\n body: asyncIterable as any, // Type assertion needed as SDK types may be strict\n });\n\n const sendStartTime = Date.now();\n\n // Use AbortController to cancel the underlying SDK request on timeout,\n // preventing leaked HTTP/2 connections if the send hangs.\n const abortController = new AbortController();\n const timeoutId = setTimeout(() => {\n this.log('[DEBUG] client.send() timeout after 5 seconds - aborting request');\n abortController.abort();\n }, 5000);\n\n let response;\n try {\n response = await this.client.send(command, { abortSignal: abortController.signal });\n } catch (error) {\n const sendDuration = Date.now() - sendStartTime;\n if (abortController.signal.aborted) {\n this.log(`[DEBUG] client.send() aborted after ${sendDuration}ms`);\n // Clean up: signal the async iterable to close and tear down client\n this._closeSignal?.();\n this.client.destroy();\n throw new Error('client.send() timeout');\n }\n this.log(`[DEBUG] client.send() error after ${sendDuration}ms:`, error);\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n\n const sendDuration = Date.now() - sendStartTime;\n this.log(`[DEBUG] client.send() completed in ${sendDuration}ms`);\n this.log('Received response from AWS Bedrock');\n\n this.stream = response.body;\n this.log(`[DEBUG] Response stream is async iterable: ${this.stream && typeof this.stream[Symbol.asyncIterator] === 'function'}`);\n this.state = 'connected';\n this.log(`[STATE] State set to 'connected'`);\n }\n\n /**\n * Process the bidirectional stream from AWS Bedrock\n */\n private async processStream(): Promise<void> {\n if (!this.stream) {\n this.log('[Stream] No stream available, cannot process');\n return;\n }\n \n // Allow re-processing if stream is still active but processingStream was reset\n // This handles the case where the stream continues but processingStream was set to false\n if (this.processingStream) {\n this.log('[Stream] Already processing stream, skipping');\n return;\n }\n\n this.processingStream = true;\n this.log('[Stream] Starting stream processing');\n\n let eventCount = 0;\n let lastEventTime = Date.now();\n \n try {\n for await (const chunk of this.stream) {\n if (chunk.chunk) {\n // Parse the chunk bytes\n const textResponse = Buffer.from(chunk.chunk.bytes || []).toString('utf-8');\n eventCount++;\n const now = Date.now();\n const timeSinceLastEvent = now - lastEventTime;\n lastEventTime = now;\n this.log(`[Stream] Received chunk #${eventCount}, length: ${textResponse.length}, time since last: ${timeSinceLastEvent}ms`);\n \n try {\n const jsonResponse = JSON.parse(textResponse);\n this.log(`[Stream] ========================================`);\n this.log(`[Stream] Parsed JSON response, keys: ${Object.keys(jsonResponse).join(', ')}`);\n \n // AWS wraps most events in an 'event' property\n // Structure: { event: { textOutput: ..., audioOutput: ..., etc } }\n // But some events like usageEvent might be at top level\n // Following AWS sample pattern exactly\n if (jsonResponse.event) {\n const eventData = jsonResponse.event as NovaSonicServerEvent;\n const eventKeys = Object.keys(jsonResponse.event);\n this.log(`[Stream] Event keys: ${eventKeys.join(', ')}`);\n \n // Handle events in the same order as AWS sample\n if (jsonResponse.event.contentStart) {\n this.log(`[Stream] → Handling contentStart`);\n this.handleServerEvent({ contentStart: jsonResponse.event.contentStart } as NovaSonicServerEvent);\n } else if (jsonResponse.event.textOutput) {\n this.log(`[Stream] → Handling textOutput, content length: ${jsonResponse.event.textOutput?.content?.length ?? 0}`);\n this.handleServerEvent({ textOutput: jsonResponse.event.textOutput } as NovaSonicServerEvent);\n } else if (jsonResponse.event.audioOutput) {\n this.handleServerEvent({ audioOutput: jsonResponse.event.audioOutput } as NovaSonicServerEvent);\n } else if (jsonResponse.event.toolUse) {\n this.handleServerEvent({ toolUse: jsonResponse.event.toolUse } as NovaSonicServerEvent);\n } else if (jsonResponse.event.contentEnd && jsonResponse.event.contentEnd.type === 'TOOL') {\n this.handleServerEvent({ contentEnd: jsonResponse.event.contentEnd } as NovaSonicServerEvent);\n } else if (jsonResponse.event.contentEnd) {\n this.log(`[Stream] Found contentEnd, type: ${jsonResponse.event.contentEnd.type}, stopReason: ${jsonResponse.event.contentEnd.stopReason}`);\n this.handleServerEvent({ contentEnd: jsonResponse.event.contentEnd } as NovaSonicServerEvent);\n } else if (jsonResponse.event.completionStart) {\n // Handle completionStart inside event object\n // According to AWS docs: completionStart signals the start of a response\n this.log('[Stream] Found completionStart inside event object:', JSON.stringify(jsonResponse.event.completionStart, null, 2));\n this.emit('completionStart', jsonResponse.event.completionStart);\n } else if (jsonResponse.event.completionEnd) {\n // Handle completionEnd inside event object\n // According to AWS docs: completionEnd with stopReason \"END_TURN\" signals turn completion\n this.log('[Stream] Found completionEnd inside event object:', JSON.stringify(jsonResponse.event.completionEnd, null, 2));\n this.handleServerEvent({ completionEnd: jsonResponse.event.completionEnd } as NovaSonicServerEvent);\n } else {\n // Handle other events - dispatch the first event key found (AWS sample pattern)\n const eventKeys = Object.keys(jsonResponse.event || {});\n this.log(`[Stream] Event keys for other events: ${eventKeys.join(', ')}`);\n if (eventKeys.length > 0) {\n // Check if completionEnd is in the event keys\n if (eventKeys.includes('completionEnd')) {\n this.log('[Stream] Found completionEnd in other events, handling explicitly');\n this.handleServerEvent({ completionEnd: jsonResponse.event.completionEnd } as NovaSonicServerEvent);\n } else {\n // Dispatch the event using the first key\n const eventKey = eventKeys[0] as keyof NovaSonicServerEvent;\n this.log(`[Stream] Dispatching other event: ${eventKey}`);\n const eventValue = jsonResponse.event[eventKey];\n if (eventValue !== undefined) {\n // Check if it's completionEnd before dispatching\n if (eventKey === 'completionEnd') {\n this.handleServerEvent({ completionEnd: eventValue } as NovaSonicServerEvent);\n } else {\n this.handleServerEvent({ [eventKey]: eventValue } as NovaSonicServerEvent);\n }\n }\n }\n } else if (Object.keys(jsonResponse).length > 0) {\n this.log(`[Stream] Unknown event structure, keys:`, Object.keys(jsonResponse).join(', '));\n }\n }\n } else {\n // Handle events that might be at top level (usageEvent, completionEnd, etc.)\n if (this.debug) {\n this.log('[Stream] Received event without \"event\" wrapper, keys:', Object.keys(jsonResponse).join(', '));\n }\n \n // Check if it's a usageEvent\n if (jsonResponse.usageEvent) {\n // Emit usage event\n this.emit('usage', {\n inputTokens: jsonResponse.usageEvent.totalInputTokens || 0,\n outputTokens: jsonResponse.usageEvent.totalOutputTokens || 0,\n totalTokens: jsonResponse.usageEvent.totalTokens || 0,\n });\n }\n \n // Check if it's a completionEnd at top level\n if (jsonResponse.completionEnd) {\n this.log('[Stream] Found completionEnd at top level:', JSON.stringify(jsonResponse.completionEnd, null, 2));\n this.handleServerEvent({ completionEnd: jsonResponse.completionEnd } as NovaSonicServerEvent);\n }\n \n // Also check if completionEnd might be directly in jsonResponse (not wrapped)\n if (!jsonResponse.event && !jsonResponse.completionEnd && !jsonResponse.usageEvent) {\n // Log the entire response to see what we're missing\n this.log('[Stream] Received response without event wrapper, keys:', Object.keys(jsonResponse).join(', '));\n }\n \n // Check if it's a completionStart at top level or in event\n if (jsonResponse.completionStart || jsonResponse.event?.completionStart) {\n const completionStart = jsonResponse.completionStart || jsonResponse.event.completionStart;\n this.log('[Stream] Found completionStart:', JSON.stringify(completionStart, null, 2));\n // Track that we've started a completion - we should expect completionEnd\n this.emit('completionStart', completionStart);\n }\n }\n } catch (parseError) {\n this.log('[Stream] Failed to parse JSON response:', textResponse.substring(0, 200));\n this.emit('error', {\n message: 'Failed to parse stream response',\n code: 'PARSE_ERROR',\n details: parseError,\n });\n }\n } else if (chunk.internalServerException) {\n this.emit('error', {\n message: 'Internal server error',\n code: 'INTERNAL_SERVER_ERROR',\n details: chunk.internalServerException,\n });\n } else if (chunk.modelStreamErrorException) {\n this.emit('error', {\n message: 'Model stream error',\n code: 'MODEL_STREAM_ERROR',\n details: chunk.modelStreamErrorException,\n });\n } else if (chunk.modelTimeoutException) {\n this.emit('error', {\n message: 'Model timeout',\n code: 'MODEL_TIMEOUT',\n details: chunk.modelTimeoutException,\n });\n } else if (chunk.serviceUnavailableException) {\n this.emit('error', {\n message: 'Service unavailable',\n code: 'SERVICE_UNAVAILABLE',\n details: chunk.serviceUnavailableException,\n });\n } else if (chunk.throttlingException) {\n this.emit('error', {\n message: 'Request throttled',\n code: 'THROTTLING',\n details: chunk.throttlingException,\n });\n } else if (chunk.validationException) {\n this.emit('error', {\n message: 'Validation error',\n code: 'VALIDATION_ERROR',\n details: chunk.validationException,\n });\n }\n }\n } catch (streamError) {\n this.log('[Stream] Error in processStream:', streamError);\n this.emit('error', {\n message: 'Stream processing error',\n code: 'STREAM_ERROR',\n details: streamError instanceof Error ? streamError.message : String(streamError),\n });\n // Don't set processingStream = false here - let it be reset in finally\n // This allows the stream to potentially recover\n } finally {\n // The for await loop exits when the stream ends (no more chunks)\n // This is normal - the stream should stay open for the entire session\n // But if the loop exits, it means AWS closed the stream or stopped sending chunks\n this.processingStream = false;\n this.log(`[Stream] processStream finished, processingStream set to false. Total events received: ${eventCount || 0}`);\n this.log(`[Stream] Stream state: state=${this.state}, stream exists=${!!this.stream}`);\n \n // CRITICAL: If the stream ends without receiving completionEnd, we need to signal turn completion\n // This handles the case where AWS closes the stream after sending all audio but before sending completionEnd\n // According to AWS docs, completionEnd should always be sent, but if the stream closes, we should still signal completion\n // CRITICAL: Only emit turnComplete if we haven't already emitted it\n // This prevents duplicate emissions when the stream restarts\n if (!this.turnCompleted && this.audioContentStarted) {\n this.log('[Stream] Stream ended but turn not completed - signaling turn completion as fallback');\n this.log(`[Stream] State: turnCompleted=${this.turnCompleted}, audioContentStarted=${this.audioContentStarted}, hasSentContentEnd=${this.hasSentContentEnd}`);\n this.turnCompleted = true;\n this.emit('turnComplete', { timestamp: Date.now() });\n \n if (this.currentResponseId) {\n const stream = this.speakerStreams.get(this.currentResponseId);\n if (stream) {\n stream.end();\n }\n this.speakerStreams.delete(this.currentResponseId);\n this.currentResponseId = undefined;\n }\n \n this.hasSentContentEnd = false;\n this.log('[Stream] Turn completion signaled, ready for next turn');\n } else if (this.turnCompleted) {\n this.log('[Stream] Stream ended and turn was already completed');\n } else {\n this.log(`[Stream] Stream ended but turn not completed - audioContentStarted=${this.audioContentStarted}, turnCompleted=${this.turnCompleted}`);\n }\n \n // CRITICAL: If the stream is still open (state is connected), we should restart processing\n // The for await loop exits when no more chunks are available, but the stream might still be open\n // We need to restart processing to handle subsequent turns\n // BUT: Only restart once per stream end, and only if we haven't already attempted a restart\n if (this.stream && this.state === 'connected' && !this.processingStream && !this.streamRestartAttempted) {\n this.log('[Stream] Stream still open but processing stopped - will restart stream processing');\n this.streamRestartAttempted = true; // Mark that we've attempted a restart\n // Restart processing in the next tick to avoid blocking\n setImmediate(() => {\n if (this.stream && this.state === 'connected' && !this.processingStream) {\n this.log('[Stream] Restarting stream processing for subsequent turns');\n this.processStream().catch((error) => {\n this.log('[Stream] Error restarting stream processing:', error);\n this.streamRestartAttempted = false; // Reset on error to allow retry\n });\n } else {\n this.streamRestartAttempted = false; // Reset if conditions changed\n }\n });\n } else {\n if (this.streamRestartAttempted) {\n this.log('[Stream] Stream restart already attempted, skipping');\n }\n }\n }\n }\n\n /**\n * Handle server events from AWS Bedrock\n */\n private handleServerEvent(event: NovaSonicServerEvent): void {\n if (this.debug) {\n this.log('Received event, keys:', Object.keys(event).join(', '));\n }\n\n if (event.contentStart) {\n this.handleContentStart(event.contentStart);\n }\n\n if (event.textOutput) {\n this.handleTextOutput(event.textOutput);\n }\n\n if (event.audioOutput?.content) {\n this.handleAudioOutput(event.audioOutput);\n }\n\n if (event.toolUse) {\n this.handleToolUse(event.toolUse);\n }\n\n if (event.contentEnd) {\n this.handleContentEnd(event.contentEnd);\n }\n\n if (event.completionEnd) {\n this.handleCompletionEnd(event.completionEnd);\n }\n\n if (event.error) {\n this.emit('error', {\n message: event.error.message || 'Unknown error',\n code: event.error.code || 'UNKNOWN_ERROR',\n details: event.error,\n });\n }\n }\n\n /**\n * Handle a contentStart event. Tracks generationStage for text content\n * blocks so the corresponding 'writing' events can be tagged\n * SPECULATIVE/FINAL for the client.\n */\n private handleContentStart(contentStart: NonNullable<NovaSonicServerEvent['contentStart']>): void {\n const role = contentStart.role?.toLowerCase() as 'assistant' | 'user' | undefined;\n // Type may not be in the type definition but exists in actual AWS responses\n const contentType = (contentStart as any).type;\n\n this.log(`[Event] contentStart: type=${contentType || 'unknown'}, role=${role}`);\n\n this.emit('contentStart', contentStart);\n\n // Track generationStage for the current text content block.\n // Nova Sonic sends SPECULATIVE (preview) then FINAL (actual transcript) for assistant text,\n // and FINAL for user ASR. This stage is included in 'writing' events so the client can\n // distinguish them and avoid showing duplicate bubbles.\n if (contentType === 'TEXT' && contentStart.additionalModelFields) {\n try {\n const additionalFields = JSON.parse(contentStart.additionalModelFields);\n this.currentTextGenerationStage = additionalFields.generationStage;\n this.log(`[Event] Text content generationStage: ${this.currentTextGenerationStage}`);\n } catch {\n this.currentTextGenerationStage = undefined;\n }\n } else if (contentType === 'TEXT') {\n this.currentTextGenerationStage = undefined;\n }\n }\n\n /**\n * Handle a textOutput event. Detects interruption (barge-in) markers in\n * the payload, otherwise emits a 'writing' event with the text and\n * current generationStage.\n */\n private handleTextOutput(textOutput: NonNullable<NovaSonicServerEvent['textOutput']>): void {\n const text = textOutput.content || '';\n const role = (textOutput.role?.toLowerCase() as 'assistant' | 'user') || 'assistant';\n\n this.log(`[Event] textOutput received: role=${role}, text length=${text.length}`);\n\n // Check for barge-in (interruption)\n let isInterrupted = false;\n try {\n const parsed = JSON.parse(text);\n if (parsed && parsed.interrupted === true) {\n isInterrupted = true;\n }\n } catch {\n // Not valid JSON — fall back to substring check\n if (/interrupted/i.test(text)) {\n isInterrupted = true;\n }\n }\n\n if (isInterrupted) {\n this.log(`[Event] Interrupt detected, emitting interrupt event`);\n this.emit('interrupt', { type: 'user', timestamp: Date.now() });\n return;\n }\n\n // Emit immediately to reduce latency.\n // Include generationStage so the client can handle SPECULATIVE vs FINAL:\n // - SPECULATIVE = preview of planned speech (arrives first)\n // - FINAL = transcript of what was actually spoken (arrives after audio)\n const generationStage = this.currentTextGenerationStage;\n this.log(`[Event] Emitting 'writing': role=${role}, generationStage=${generationStage}, length=${text.length}`);\n this.emit('writing', { text, role, generationStage });\n }\n\n /**\n * Handle an audioOutput event. Decodes the base64 LPCM payload, emits\n * 'speaking' with both the base64 string and an Int16Array view, and\n * forwards bytes to any active speaker stream.\n */\n private handleAudioOutput(audioOutput: NonNullable<NovaSonicServerEvent['audioOutput']>): void {\n try {\n const content = audioOutput.content as string;\n const audioBytes = Buffer.from(content, 'base64');\n\n this.log(`[Event] Audio output: ${audioBytes.length} bytes`);\n\n // Mark that we're receiving assistant audio output\n this.isReceivingAssistantAudio = true;\n\n // Produce Int16Array view matching the declared type (LPCM 16-bit samples)\n const audioData = new Int16Array(audioBytes.buffer, audioBytes.byteOffset, audioBytes.byteLength / 2);\n\n this.emit('speaking', {\n audio: content,\n audioData,\n response_id: this.currentResponseId,\n });\n\n // Also emit to speaker stream\n if (this.currentResponseId) {\n const stream = this.speakerStreams.get(this.currentResponseId);\n if (stream) {\n stream.write(audioBytes);\n }\n }\n } catch (error) {\n this.log('[Event] Error decoding audio:', error);\n this.emit('error', {\n message: 'Failed to decode audio',\n code: 'AUDIO_DECODE_ERROR',\n details: error,\n });\n }\n }\n\n /**\n * Handle a toolUse event. Emits 'toolCall' and dispatches to the\n * configured tool's execute() function via handleToolCall().\n */\n private handleToolUse(toolUse: NonNullable<NovaSonicServerEvent['toolUse']>): void {\n const toolUseId = toolUse.toolUseId || '';\n const toolName = toolUse.toolName || '';\n const toolInput = toolUse.input || {};\n\n this.emit('toolCall', {\n name: toolName,\n args: toolInput,\n id: toolUseId,\n });\n\n if (this.tools && toolName in this.tools) {\n this.handleToolCall(toolName, toolInput, toolUseId);\n }\n }\n\n /**\n * Handle a contentEnd event. Forwards it to clients, then routes by\n * stopReason / type:\n * - INTERRUPTED: emit 'interrupt' and tear down the active speaker stream\n * - TOOL: end the active speaker stream\n * - AUDIO with END_TURN: signal turnComplete (assistant audio finished)\n * - AUDIO with PARTIAL_TURN while receiving assistant audio: schedule\n * fallback turnComplete in case completionEnd never arrives\n * - AUDIO otherwise: user input ended, reset turn flags\n */\n private handleContentEnd(contentEnd: NonNullable<NovaSonicServerEvent['contentEnd']>): void {\n this.log(`[Event] contentEnd received: type=${contentEnd.type}, stopReason=${contentEnd.stopReason}`);\n\n // Emit contentEnd event (AWS sample forwards this directly to clients)\n this.emit('contentEnd', contentEnd);\n\n // Check for interruption (barge-in) - stopReason can be in contentEnd\n if (contentEnd.stopReason === 'INTERRUPTED') {\n this.log('[Event] Content interrupted by user (barge-in)');\n this.emit('interrupt', { type: 'user', timestamp: Date.now() });\n \n // Clear audio playback buffer immediately\n if (this.currentResponseId) {\n const stream = this.speakerStreams.get(this.currentResponseId);\n if (stream) {\n stream.destroy(); // Destroy instead of end to immediately stop\n }\n this.speakerStreams.delete(this.currentResponseId);\n }\n this.currentResponseId = undefined;\n \n // Following AWS sample: even after interruption, we keep audioContentStarted=true\n // and reuse the same audioContentName. We just continue with audioInput chunks.\n this.log('[Event] After interruption, keeping audioContentStarted=true for continued streaming');\n // DO NOT reset audioContentName - it persists for the entire session\n } else if (contentEnd.type === 'TOOL' && this.currentResponseId) {\n // Tool execution completed\n const stream = this.speakerStreams.get(this.currentResponseId);\n if (stream) {\n stream.end();\n }\n } else if (contentEnd.type === 'AUDIO') {\n // Audio content ended - this could be user input ending OR assistant output ending\n // According to AWS documentation:\n // - contentEnd (AUDIO) with stopReason \"PARTIAL_TURN\" or \"END_TURN\" marks end of audio content\n // - completionEnd with stopReason \"END_TURN\" signals turn completion\n // However, AWS may not always send completionEnd, so we need a fallback\n // If we receive contentEnd (AUDIO) with END_TURN for assistant output, we should signal turn complete\n // But we'll wait a bit to see if more audio chunks arrive\n if (contentEnd.stopReason === 'END_TURN') {\n // This is assistant audio output ending with END_TURN\n // According to AWS docs: contentEnd (AUDIO) with END_TURN marks end of audio content\n // completionEnd should follow, but if it doesn't, we should still signal turn completion\n // We'll emit turnComplete immediately, but also wait for completionEnd as the definitive signal\n this.log(`[Event] contentEnd (AUDIO) with stopReason END_TURN - signaling turn complete`);\n \n // End the audio stream\n if (this.currentResponseId) {\n const stream = this.speakerStreams.get(this.currentResponseId);\n if (stream) {\n stream.end();\n }\n this.speakerStreams.delete(this.currentResponseId);\n this.currentResponseId = undefined;\n }\n \n // Emit turnComplete immediately (frontend is already handling contentEnd with END_TURN)\n // But also set a flag to check if completionEnd arrives (which would be the definitive signal)\n // CRITICAL: Only emit once - check turnCompleted flag to prevent duplicate emissions\n if (!this.turnCompleted) {\n this.turnCompleted = true;\n this.emit('turnComplete', { timestamp: Date.now() });\n this.hasSentContentEnd = false;\n this.log(`[Event] Turn complete (from contentEnd AUDIO with END_TURN), ready for next turn. audioContentStarted: ${this.audioContentStarted}, audioContentName: ${this.audioContentName}`);\n } else {\n this.log(`[Event] contentEnd (AUDIO) with END_TURN received but turn already completed - skipping duplicate turnComplete emission`);\n }\n \n // Set a timeout to clear any pending state if completionEnd doesn't arrive\n // This is just for cleanup, not for signaling (we already signaled above)\n if (!this.turnCompleteTimeout) {\n this.turnCompleteTimeout = setTimeout(() => {\n // If completionEnd hasn't arrived, that's okay - we already signaled turn completion\n this.log(`[Event] Timeout: completionEnd not received, but turn already completed from contentEnd`);\n this.turnCompleteTimeout = undefined;\n }, 1000); // Short timeout just for logging\n }\n } else {\n // This is user audio input ending (stopReason might be undefined or PARTIAL_TURN)\n // OR assistant audio output ending with PARTIAL_TURN\n // Following AWS sample: contentStart (AUDIO) is sent ONCE at the beginning\n // and NEVER reset. We just continue sending audioInput chunks for subsequent turns.\n // DO NOT reset audioContentStarted - it stays true for the entire session\n // DO NOT reset audioContentName - it persists for the entire session\n \n // If this is assistant audio output ending (we were receiving assistant audio), \n // and stopReason is PARTIAL_TURN, we should wait for completionEnd\n // But if completionEnd doesn't arrive, we'll use a fallback timeout\n if (this.isReceivingAssistantAudio && contentEnd.stopReason === 'PARTIAL_TURN') {\n // This is assistant output ending - wait for completionEnd\n // Set a fallback timeout to emit turnComplete if completionEnd doesn't arrive\n this.isReceivingAssistantAudio = false; // Reset flag\n if (!this.turnCompleteTimeout && !this.turnCompleted) {\n this.log(`[Event] contentEnd (AUDIO) with PARTIAL_TURN for assistant output - waiting for completionEnd, setting fallback timeout`);\n this.turnCompleteTimeout = setTimeout(() => {\n if (!this.turnCompleted) {\n this.log(`[Event] Fallback: completionEnd not received after contentEnd (AUDIO) with PARTIAL_TURN, signaling turn complete`);\n this.turnCompleted = true;\n this.emit('turnComplete', { timestamp: Date.now() });\n \n if (this.currentResponseId) {\n const stream = this.speakerStreams.get(this.currentResponseId);\n if (stream) {\n stream.end();\n }\n this.speakerStreams.delete(this.currentResponseId);\n this.currentResponseId = undefined;\n }\n \n this.hasSentContentEnd = false;\n this.turnCompleteTimeout = undefined;\n }\n }, 2000); // 2 second timeout (reduced from 3)\n }\n } else {\n // This is user audio input ending\n // Reset hasSentContentEnd flag to allow sending contentEnd for the next turn\n // Also reset turnCompleted flag to allow new user input\n this.hasSentContentEnd = false;\n this.turnCompleted = false; // Reset for next turn\n this.log(`[Event] contentEnd (AUDIO) - user input ended, stopReason: ${contentEnd.stopReason}. Keeping audioContentStarted=true for next turn. Reset hasSentContentEnd=false, turnCompleted=false.`);\n }\n }\n } else if (contentEnd.type === 'TEXT') {\n // Text content ended — clear generationStage tracking\n this.currentTextGenerationStage = undefined;\n // IMPORTANT: Do NOT emit turnComplete here. Nova Sonic sends one contentEnd(TEXT) per\n // text content block, so emitting turnComplete here would fire multiple times per turn.\n // The definitive turn-completion signal comes from completionEnd (line ~1278) or\n // contentEnd(AUDIO, END_TURN) (line ~1171), both of which have proper guards.\n this.log(`[Event] contentEnd (TEXT) received, stopReason: ${contentEnd.stopReason}. Turn completion handled by completionEnd/contentEnd(AUDIO).`);\n if (contentEnd.stopReason === 'END_TURN') {\n this.hasSentContentEnd = false;\n }\n }\n }\n\n /**\n * Handle a completionEnd event. AWS uses this as the definitive signal\n * that a turn (and all audio output) has finished. Tears down the active\n * speaker stream, clears any fallback timer, emits 'turnComplete' once,\n * and forwards token usage if reported.\n */\n private handleCompletionEnd(completionEnd: NonNullable<NovaSonicServerEvent['completionEnd']>): void {\n this.log(`[Event] completionEnd received, stopReason: ${completionEnd.stopReason}`);\n\n // Clear the fallback timeout if it was set\n if (this.turnCompleteTimeout) {\n clearTimeout(this.turnCompleteTimeout);\n this.turnCompleteTimeout = undefined;\n }\n\n // CRITICAL: End the audio stream BEFORE emitting turnComplete so all audio\n // chunks have been received before we signal turn completion.\n if (this.currentResponseId) {\n const stream = this.speakerStreams.get(this.currentResponseId);\n if (stream) {\n stream.end();\n }\n this.speakerStreams.delete(this.currentResponseId);\n this.currentResponseId = undefined;\n }\n\n this.isReceivingAssistantAudio = false;\n\n // Emit turnComplete for ANY completionEnd (AWS should send END_TURN, but be lenient).\n // Only emit once - turnCompleted flag prevents duplicate emissions when contentEnd\n // (AUDIO with END_TURN) already signaled turn completion.\n if (!this.turnCompleted) {\n this.log(`[Event] completionEnd - signaling turn complete (stopReason: ${completionEnd.stopReason || 'undefined'})`);\n this.turnCompleted = true;\n this.emit('turnComplete', { timestamp: Date.now() });\n this.hasSentContentEnd = false;\n } else {\n this.log(`[Event] completionEnd received but turn already completed - skipping duplicate turnComplete emission`);\n }\n\n if (completionEnd.usage) {\n this.emit('usage', {\n inputTokens: completionEnd.usage.inputTokens || 0,\n outputTokens: completionEnd.usage.outputTokens || 0,\n totalTokens:\n (completionEnd.usage.inputTokens || 0) +\n (completionEnd.usage.outputTokens || 0),\n });\n }\n }\n\n /**\n * Handle tool execution\n */\n private async handleToolCall(toolName: string, args: Record<string, any>, toolUseId: string): Promise<void> {\n const tool = this.tools?.[toolName];\n if (!tool || !tool.execute) {\n this.emit('error', {\n message: `Tool ${toolName} not found or has no execute function`,\n code: 'TOOL_NOT_FOUND',\n });\n return;\n }\n\n try {\n // Execute tool\n const result = await tool.execute(\n { context: args, requestContext: this.requestContext },\n {\n toolCallId: toolUseId,\n messages: [],\n },\n );\n\n // Send tool result back to the model\n await this.sendClientEvent({\n toolResult: {\n toolUseId,\n content: [\n {\n json: typeof result === 'object' ? result : { result },\n },\n ],\n },\n });\n } catch (error) {\n this.emit('error', {\n message: `Error executing tool ${toolName}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n code: 'TOOL_EXECUTION_ERROR',\n details: error,\n });\n\n // Send error result back\n await this.sendClientEvent({\n toolResult: {\n toolUseId,\n content: [\n {\n text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,\n },\n ],\n },\n });\n }\n }\n\n /**\n * Send a client event to AWS Bedrock\n * Events are sent through the input stream that was passed to the bidirectional stream command\n */\n private async sendClientEvent(event: NovaSonicClientEvent): Promise<void> {\n if (this.state !== 'connected') {\n throw new NovaSonicError(\n ErrorCode.NOT_CONNECTED,\n 'Not connected to AWS Bedrock. Call connect() first.',\n );\n }\n\n try {\n // Add event to queue and signal (following AWS sample pattern)\n const eventQueue = this._eventQueue;\n const signalQueue = this._signalQueue;\n \n if (!eventQueue || !signalQueue) {\n throw new NovaSonicError(\n ErrorCode.NOT_CONNECTED,\n 'Event queue not initialized. Connection may not be fully established.',\n );\n }\n \n this.log(`[sendClientEvent] Adding event to queue (queue size: ${eventQueue.length})`);\n eventQueue.push({ event });\n this.log(`[sendClientEvent] Event added, queue size now: ${eventQueue.length}, signaling...`);\n signalQueue(); // Signal that data is available\n this.log(`[sendClientEvent] Signal sent`);\n \n if (this.debug) {\n this.log('Sent client event, keys:', Object.keys(event).join(', '));\n }\n } catch (error) {\n throw new NovaSonicError(\n ErrorCode.WEBSOCKET_ERROR,\n `Failed to send client event: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error,\n );\n }\n }\n\n /**\n * Disconnects from the AWS Bedrock session and cleans up resources.\n *\n * Pushes a `sessionEnd` event to the queue before signalling close,\n * then schedules client destruction on the next tick so the async\n * iterator has a chance to yield the event to the SDK.\n */\n close(): void {\n if (this.state === 'disconnected') {\n return;\n }\n\n this.state = 'disconnected';\n this.processingStream = false;\n\n // Clear fallback turn-complete timeout to prevent callbacks after teardown\n if (this.turnCompleteTimeout) {\n clearTimeout(this.turnCompleteTimeout);\n this.turnCompleteTimeout = undefined;\n }\n\n // Push sessionEnd so the server can acknowledge the close before we\n // tear down the HTTP/2 connection. Signal the queue so the iterator\n // yields this event on its next pull.\n const eventQueue = this._eventQueue;\n const signalQueue = this._signalQueue;\n if (eventQueue && signalQueue) {\n eventQueue.push({ event: { sessionEnd: {} } });\n signalQueue();\n }\n\n // Signal close *after* the sessionEnd event has been enqueued so the\n // iterator returns done:true only after yielding sessionEnd.\n const closeSignal = this._closeSignal;\n if (closeSignal) {\n closeSignal();\n }\n\n // Close input stream if it exists\n if (this.inputStream) {\n this.inputStream.end();\n this.inputStream = undefined;\n }\n\n // End all speaker streams\n for (const stream of this.speakerStreams.values()) {\n stream.end();\n }\n this.speakerStreams.clear();\n\n // Delay client destruction so the iterator has a chance to drain\n // the sessionEnd event to the SDK before the HTTP/2 session is torn down.\n const client = this.client;\n this.client = undefined;\n this.stream = undefined;\n if (client) {\n setImmediate(() => {\n if (typeof client.destroy === 'function') {\n client.destroy();\n }\n });\n }\n\n this.log('Disconnected from AWS Bedrock Nova 2 Sonic');\n }\n\n /**\n * Equips the voice instance with a set of instructions.\n */\n addInstructions(instructions?: string): void {\n this.instructions = instructions;\n }\n\n /**\n * Equips the voice instance with a set of tools.\n */\n addTools(tools?: ToolsInput): void {\n this.tools = tools || {};\n }\n\n /**\n * Convert text to speech\n */\n async speak(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: string } & NovaSonicVoiceOptions,\n ): Promise<void> {\n if (this.state !== 'connected') {\n throw new NovaSonicError(\n ErrorCode.NOT_CONNECTED,\n 'Not connected. Call connect() first.',\n );\n }\n\n // Convert stream to string if needed\n let text = '';\n if (typeof input !== 'string') {\n const chunks: Buffer[] = [];\n for await (const chunk of input) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n text = Buffer.concat(chunks).toString('utf-8');\n } else {\n text = input;\n }\n\n if (text.trim().length === 0) {\n throw new NovaSonicError(ErrorCode.VALIDATION_ERROR, 'Input text is empty');\n }\n\n // Generate a response ID for this turn\n this.currentResponseId = `response-${Date.now()}`;\n const speakerStream = new PassThrough() as StreamWithId;\n speakerStream.id = this.currentResponseId;\n this.speakerStreams.set(this.currentResponseId, speakerStream);\n this.emit('speaker', speakerStream);\n\n // Send text input event\n // Note: textInput in speak() is a simplified version for backward compatibility\n // For full control, use send() with proper contentStart/textInput/contentEnd sequence\n const promptName = this._promptName;\n if (!promptName) {\n throw new NovaSonicError(\n ErrorCode.NOT_CONNECTED,\n 'Prompt name not initialized. Connection may not be fully established.',\n );\n }\n\n // Prompt should already be started during connection\n // Do NOT call startPrompt() here as it would send a duplicate promptStart\n // and AWS requires the first content after promptStart to be SYSTEM role\n if (!this.promptStarted) {\n throw new NovaSonicError(\n ErrorCode.INVALID_STATE,\n 'Prompt not started. This should not happen - prompt should be started during connection.',\n );\n }\n\n const contentName = randomUUID();\n // Content start\n await this.sendClientEvent({\n contentStart: {\n promptName,\n contentName,\n type: \"TEXT\",\n interactive: true,\n role: \"USER\",\n textInputConfiguration: {\n mediaType: \"text/plain\",\n },\n },\n });\n // Text input\n await this.sendClientEvent({\n textInput: {\n promptName,\n contentName,\n content: text,\n },\n });\n // Content end\n await this.sendClientEvent({\n contentEnd: {\n promptName,\n contentName,\n },\n });\n }\n\n /**\n * Convert speech to text (transcription)\n * For Nova Sonic, this is the same as send() - both stream audio input\n */\n async listen(\n audioStream: NodeJS.ReadableStream | unknown,\n options?: NovaSonicVoiceOptions,\n ): Promise<void> {\n // For Nova Sonic, listen() and send() are the same - both stream audio\n // Convert to Int16Array or ReadableStream format expected by send()\n if (audioStream && typeof audioStream === 'object' && 'read' in audioStream) {\n await this.send(audioStream as NodeJS.ReadableStream);\n } else {\n throw new NovaSonicError(\n ErrorCode.INVALID_AUDIO_FORMAT,\n 'Unsupported audio stream format for listen()',\n );\n }\n }\n\n /**\n * Streams audio data in real-time to the AWS Bedrock service.\n * Following AWS Nova 2 Sonic event sequence:\n * 1. contentStart (AUDIO, USER) - if not already sent\n * 2. audioInput events (one per chunk)\n * 3. contentEnd - when audio stream ends (handled separately via endAudioInput)\n */\n async send(audioData: NodeJS.ReadableStream | Int16Array): Promise<void> {\n this.log(`[send] Current state: ${this.state}`);\n if (this.state !== 'connected') {\n this.log(`[send] ERROR: State is '${this.state}', expected 'connected'`);\n throw new NovaSonicError(\n ErrorCode.NOT_CONNECTED,\n `Not connected. Current state: ${this.state}. Call connect() first.`,\n );\n }\n this.log(`[send] State check passed, proceeding with send`);\n\n // Validate audio format early, before any network operations\n if (!(audioData instanceof Int16Array) && !(audioData && typeof audioData === 'object' && 'read' in audioData)) {\n throw new NovaSonicError(\n ErrorCode.INVALID_AUDIO_FORMAT,\n 'Unsupported audio data format',\n );\n }\n\n // Reset turnCompleted flag when user starts speaking again (new turn)\n // According to AWS sample: contentStart (AUDIO) is sent ONCE at the beginning and the same\n // audioContentId is reused for ALL turns. We do NOT send a new contentStart after turn completion.\n // We just continue sending audioInput chunks using the same audioContentName.\n // CRITICAL: Always reset hasSentContentEnd when starting a new turn (sending new audio)\n // This ensures we can send contentEnd for the new turn even if the previous turn didn't complete properly\n if (this.turnCompleted || this.hasSentContentEnd) {\n this.log(`[send] Starting new turn - resetting flags. turnCompleted=${this.turnCompleted}, hasSentContentEnd=${this.hasSentContentEnd}.`);\n const needNewContent = this.hasSentContentEnd;\n this.turnCompleted = false;\n this.hasSentContentEnd = false;\n this.streamRestartAttempted = false;\n if (needNewContent) {\n // contentEnd was sent (via endAudioInput), which closed the audio content container.\n // AWS docs: \"All audio frames share a single content container until the conversation\n // ends and it is explicitly closed.\" Since it was explicitly closed, we need a new\n // contentStart with a new contentName for subsequent audio.\n this.audioContentStarted = false;\n this.log(`[send] contentEnd was previously sent - will create new audio content container`);\n }\n this.log(`[send] State reset: turnCompleted=false, hasSentContentEnd=false, audioContentStarted=${this.audioContentStarted}`);\n }\n\n // promptStart is now sent during connection, so we just need to ensure audio contentStart is sent\n // Mark prompt as started (it was sent during connection)\n if (!this.promptStarted) {\n this.promptStarted = true;\n }\n\n // Send AUDIO contentStart on first send() call if not already sent\n // We don't send it during connection to avoid AWS waiting for audio when using text input\n const promptName = this._promptName;\n if (!promptName) {\n throw new NovaSonicError(\n ErrorCode.NOT_CONNECTED,\n 'Prompt name not initialized. Connection may not be fully established.',\n );\n }\n if (!this.audioContentStarted) {\n // First time sending audio - need to send contentStart first\n const audioContentId = randomUUID();\n this.audioContentName = audioContentId;\n \n this.log(`[send] First audio send - sending AUDIO contentStart with contentName: ${audioContentId}`);\n \n await this.sendClientEvent({\n contentStart: {\n promptName,\n contentName: audioContentId,\n type: \"AUDIO\",\n interactive: true,\n role: \"USER\",\n audioInputConfiguration: {\n mediaType: \"audio/lpcm\",\n sampleRateHertz: 16000,\n sampleSizeBits: 16,\n channelCount: 1,\n encoding: \"base64\",\n audioType: \"SPEECH\",\n },\n },\n });\n \n this.audioContentStarted = true;\n this.log(`[send] AUDIO contentStart sent, ready to stream audio`);\n } else {\n this.log(`[send] AUDIO contentStart already sent, sending audioInput chunks directly`);\n }\n \n if (!this.audioContentName) {\n throw new NovaSonicError(\n ErrorCode.INVALID_STATE,\n 'Audio content name not initialized. This should not happen.',\n );\n }\n const contentName = this.audioContentName;\n\n // Convert to base64 and send as audioInput events (AWS expects 'audioInput', not 'audioInputChunk')\n if (audioData instanceof Int16Array) {\n const buffer = Buffer.from(audioData.buffer, audioData.byteOffset, audioData.byteLength);\n const base64Audio = buffer.toString('base64');\n this.log(`[send] Sending audioInput chunk, size: ${buffer.length} bytes, contentName: ${contentName}, turnCompleted: ${this.turnCompleted}, hasSentContentEnd: ${this.hasSentContentEnd}, audioContentStarted: ${this.audioContentStarted}, state: ${this.state}`);\n \n // Verify stream is still active\n if (this.state !== 'connected') {\n this.log(`[send] ERROR: State changed to '${this.state}' during send!`);\n throw new NovaSonicError(\n ErrorCode.NOT_CONNECTED,\n `Connection lost during send. State: ${this.state}`,\n );\n }\n \n await this.sendClientEvent({\n audioInput: {\n promptName,\n contentName,\n content: base64Audio,\n },\n });\n this.log(`[send] audioInput chunk sent successfully`);\n } else if (audioData && typeof audioData === 'object' && 'read' in audioData) {\n const stream = audioData as NodeJS.ReadableStream;\n for await (const chunk of stream) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n const base64Audio = buffer.toString('base64');\n this.log(`[send] Sending audioInput chunk from stream, size: ${buffer.length} bytes, contentName: ${contentName}, turnCompleted: ${this.turnCompleted}, hasSentContentEnd: ${this.hasSentContentEnd}`);\n await this.sendClientEvent({\n audioInput: {\n promptName,\n contentName,\n content: base64Audio,\n },\n });\n }\n } else {\n throw new NovaSonicError(\n ErrorCode.INVALID_AUDIO_FORMAT,\n 'Unsupported audio data format',\n );\n }\n }\n\n /**\n * End audio input stream (sends contentEnd for audio)\n * Call this when done sending audio chunks\n */\n async endAudioInput(): Promise<void> {\n // Prevent sending contentEnd multiple times for the same turn\n if (this.hasSentContentEnd) {\n this.log('[endAudioInput] contentEnd already sent for this turn, skipping');\n return;\n }\n \n // Prevent sending contentEnd if turn has already been completed by AWS\n // This can happen if the frontend sends contentEnd after AWS has already signaled turn completion\n if (this.turnCompleted) {\n this.log('[endAudioInput] Turn already completed by AWS, skipping contentEnd. Resetting turnCompleted flag for next turn.');\n this.turnCompleted = false; // Reset for next turn\n this.hasSentContentEnd = false; // Reset flag\n return;\n }\n \n if (this.audioContentStarted && this.audioContentName && this._promptName) {\n const promptName = this._promptName;\n this.log('[endAudioInput] Sending contentEnd for audio input');\n await this.sendClientEvent({\n contentEnd: {\n promptName,\n contentName: this.audioContentName,\n },\n });\n this.hasSentContentEnd = true; // Mark that we've sent contentEnd\n // Don't reset state here - it will be reset when we receive contentEnd.type === 'AUDIO' from AWS\n } else {\n this.log('[endAudioInput] Cannot send contentEnd: audioContentStarted=' + this.audioContentStarted + ', audioContentName=' + this.audioContentName);\n }\n }\n\n /**\n * Register an event listener\n */\n on<E extends VoiceEventType>(\n event: E,\n callback: (data: E extends keyof NovaSonicEventMap ? NovaSonicEventMap[E] : unknown) => void,\n ): void {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n this.events[event].push(callback as EventCallback);\n }\n\n /**\n * Remove an event listener\n */\n off<E extends VoiceEventType>(\n event: E,\n callback: (data: E extends keyof NovaSonicEventMap ? NovaSonicEventMap[E] : unknown) => void,\n ): void {\n if (!this.events[event]) {\n return;\n }\n const index = this.events[event].indexOf(callback as EventCallback);\n if (index !== -1) {\n this.events[event].splice(index, 1);\n }\n }\n\n /**\n * Emit an event with arguments\n */\n private emit(event: string, data: unknown): void {\n if (!this.events[event]) {\n this.log(`[NovaSonic] emit('${event}'): No listeners registered for this event`);\n return;\n }\n const listenerCount = this.events[event].length;\n this.log(`[NovaSonic] emit('${event}'): Calling ${listenerCount} listener(s)`);\n for (const callback of this.events[event]) {\n try {\n callback(data);\n this.log(`[NovaSonic] emit('${event}'): Successfully called one listener`);\n } catch (error) {\n this.log(`Error in event handler for ${event}:`, error);\n }\n }\n this.log(`[NovaSonic] emit('${event}'): Finished calling all ${listenerCount} listener(s)`);\n }\n\n /**\n * Get listener status\n */\n async getListener(): Promise<{ enabled: boolean }> {\n return { enabled: this.state === 'connected' };\n }\n\n /**\n * Log helper\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[NovaSonicVoice]', ...args);\n }\n }\n}\n\n"]}
|