@dtelecom/agents-js 0.1.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/LICENSE +190 -0
- package/README.md +153 -0
- package/dist/chunk-6OWWB2X7.mjs +17 -0
- package/dist/chunk-6OWWB2X7.mjs.map +1 -0
- package/dist/chunk-BN7PIFNJ.mjs +54 -0
- package/dist/chunk-BN7PIFNJ.mjs.map +1 -0
- package/dist/chunk-RQKGHAFV.mjs +412 -0
- package/dist/chunk-RQKGHAFV.mjs.map +1 -0
- package/dist/index.d.mts +343 -0
- package/dist/index.d.ts +343 -0
- package/dist/index.js +1750 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1201 -0
- package/dist/index.mjs.map +1 -0
- package/dist/providers/index.d.mts +142 -0
- package/dist/providers/index.d.ts +142 -0
- package/dist/providers/index.js +613 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/index.mjs +524 -0
- package/dist/providers/index.mjs.map +1 -0
- package/dist/room-memory-VAREPHY6.mjs +8 -0
- package/dist/room-memory-VAREPHY6.mjs.map +1 -0
- package/dist/types-Cs5uUoTC.d.mts +259 -0
- package/dist/types-Cs5uUoTC.d.ts +259 -0
- package/package.json +89 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/voice-agent.ts","../src/room/room-connection.ts","../src/room/audio-input.ts","../src/room/audio-output.ts","../src/core/pipeline.ts","../src/core/context-manager.ts","../src/core/sentence-splitter.ts","../src/core/turn-detector.ts","../src/core/barge-in.ts"],"sourcesContent":["/**\n * VoiceAgent — top-level orchestrator for AI voice agents in dTelecom rooms.\n *\n * Wires together:\n * - RoomConnection (join room, publish audio track)\n * - Pipeline (STT -> LLM -> TTS)\n * - AudioInput (per-participant audio streams)\n * - AudioOutput (agent's published audio)\n * - RoomMemory (optional persistent memory)\n */\n\nimport { EventEmitter } from 'events';\nimport type { RemoteAudioTrack, RemoteTrackPublication, RemoteParticipant } from '@dtelecom/server-sdk-node';\nimport { RoomConnection } from '../room/room-connection';\nimport { AudioInput } from '../room/audio-input';\nimport { AudioOutput } from '../room/audio-output';\nimport { Pipeline } from './pipeline';\nimport type { AgentConfig, AgentStartOptions, DataMessageHandler } from './types';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('VoiceAgent');\n\nexport class VoiceAgent extends EventEmitter {\n private readonly config: AgentConfig;\n private connection: RoomConnection | null = null;\n private pipeline: Pipeline | null = null;\n private audioInputs = new Map<string, AudioInput>();\n private audioOutput: AudioOutput | null = null;\n private memory: import('../memory/room-memory').RoomMemory | null = null;\n private _running = false;\n\n constructor(config: AgentConfig) {\n super();\n this.config = config;\n }\n\n get running(): boolean {\n return this._running;\n }\n\n get room() { return this.connection?.room ?? null; }\n\n /** Enable saving raw TTS audio as WAV files to `dir` for debugging. */\n enableAudioDump(dir: string): void {\n this._dumpDir = dir;\n if (this.audioOutput) {\n this.audioOutput.dumpDir = dir;\n }\n }\n private _dumpDir: string | null = null;\n\n /**\n * Speak text directly via TTS, bypassing the LLM.\n * Use for greetings or announcements. Supports barge-in.\n */\n async say(text: string): Promise<void> {\n if (!this.pipeline) {\n throw new Error('Agent not started — call start() first');\n }\n await this.pipeline.say(text);\n }\n\n /** Start the agent — connect to room and begin listening. */\n async start(options: AgentStartOptions): Promise<void> {\n if (this._running) {\n throw new Error('Agent is already running');\n }\n\n log.info(`Starting agent for room \"${options.room}\"...`);\n\n // 1. Initialize memory (if enabled)\n if (this.config.memory?.enabled) {\n const { RoomMemory } = await import('../memory/room-memory');\n this.memory = new RoomMemory({\n dbPath: this.config.memory.dbPath ?? './data/memory.db',\n room: options.room,\n });\n await this.memory.init();\n this.memory.startSession();\n log.info('Memory initialized');\n }\n\n // 2. Connect to room\n this.connection = new RoomConnection();\n await this.connection.connect({\n room: options.room,\n apiKey: options.apiKey,\n apiSecret: options.apiSecret,\n identity: options.identity ?? 'agent',\n name: options.name ?? options.identity ?? 'AI Agent',\n });\n\n // 3. Publish audio track + start sending silence to keep it active\n const source = await this.connection.publishAudioTrack();\n this.audioOutput = new AudioOutput(source);\n if (this._dumpDir) this.audioOutput.dumpDir = this._dumpDir;\n this.audioOutput.startSilence();\n\n // 4. Create pipeline\n this.pipeline = new Pipeline({\n stt: this.config.stt,\n llm: this.config.llm,\n tts: this.config.tts,\n instructions: this.config.instructions,\n audioOutput: this.audioOutput,\n respondMode: this.config.respondMode,\n agentName: this.config.agentName,\n nameVariants: this.config.nameVariants,\n memory: this.memory ?? undefined,\n });\n\n // Forward pipeline events\n this.pipeline.on('transcription', (result) => this.emit('transcription', result));\n this.pipeline.on('sentence', (text) => this.emit('sentence', text));\n this.pipeline.on('response', (text) => this.emit('response', text));\n this.pipeline.on('agentState', (state) => this.emit('agentState', state));\n this.pipeline.on('error', (error) => this.emit('error', error));\n\n // 5. Subscribe to existing remote participants\n for (const participant of this.connection.room.remoteParticipants.values()) {\n for (const [, pub] of participant.trackPublications) {\n if (pub.track) {\n this.handleTrackSubscribed(pub.track as RemoteAudioTrack, pub as RemoteTrackPublication, participant);\n }\n }\n }\n\n // 6. Listen for new tracks\n this.connection.room.on('trackSubscribed', (track, pub, participant) => {\n this.handleTrackSubscribed(track, pub, participant);\n });\n\n this.connection.room.on('trackUnsubscribed', (track, _pub, participant) => {\n this.handleTrackUnsubscribed(track, participant);\n });\n\n this.connection.room.on('participantDisconnected', (participant) => {\n this.handleParticipantDisconnected(participant);\n });\n\n this.connection.room.on('disconnected', (reason) => {\n log.info(`Room disconnected: ${reason}`);\n this.emit('disconnected', reason);\n });\n\n // 7. Data channel support\n if (this.config.onDataMessage) {\n this.setupDataChannel(this.config.onDataMessage);\n }\n\n this._running = true;\n this.emit('connected');\n log.info('Agent started and listening');\n }\n\n /** Stop the agent — disconnect and clean up. */\n async stop(): Promise<void> {\n if (!this._running) return;\n\n log.info('Stopping agent...');\n this._running = false;\n\n if (this.pipeline) {\n await this.pipeline.stop();\n this.pipeline = null;\n }\n\n // End memory session (generates summary)\n if (this.memory) {\n try {\n await this.memory.endSession(this.config.llm);\n await this.memory.close();\n } catch (err) {\n log.error('Error closing memory:', err);\n }\n this.memory = null;\n }\n\n for (const [, input] of this.audioInputs) {\n input.close();\n }\n this.audioInputs.clear();\n\n if (this.audioOutput) {\n this.audioOutput.stop();\n this.audioOutput = null;\n }\n\n if (this.connection) {\n await this.connection.disconnect();\n this.connection = null;\n }\n\n this.emit('disconnected', 'agent_stopped');\n log.info('Agent stopped');\n }\n\n private setupDataChannel(handler: DataMessageHandler): void {\n if (!this.connection) return;\n\n this.connection.room.on('dataReceived', (payload: Uint8Array, participant?: RemoteParticipant, _kind?: unknown, topic?: string) => {\n const identity = participant?.identity ?? 'unknown';\n handler(payload, identity, topic);\n });\n\n log.info('Data channel handler registered');\n }\n\n private handleTrackSubscribed(\n track: RemoteAudioTrack,\n _publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): void {\n const identity = participant.identity;\n log.info(`Track subscribed from \"${identity}\" (sid=${track.sid})`);\n\n // Track participant in memory\n this.memory?.addParticipant(identity);\n\n // Close existing AudioInput if this is a re-subscription\n const existing = this.audioInputs.get(identity);\n if (existing) {\n log.info(`Closing old AudioInput for \"${identity}\" (re-subscription)`);\n existing.close();\n }\n\n const audioInput = new AudioInput(track, identity);\n this.audioInputs.set(identity, audioInput);\n\n const sttStream = this.pipeline!.addParticipant(identity);\n\n this.pipeAudioToSTT(audioInput, sttStream, identity);\n }\n\n private handleTrackUnsubscribed(\n _track: RemoteAudioTrack,\n participant: RemoteParticipant,\n ): void {\n const identity = participant.identity;\n log.info(`Track unsubscribed from \"${identity}\"`);\n\n const input = this.audioInputs.get(identity);\n if (input) {\n input.close();\n this.audioInputs.delete(identity);\n }\n }\n\n private handleParticipantDisconnected(participant: RemoteParticipant): void {\n const identity = participant.identity;\n log.info(`Participant disconnected: \"${identity}\"`);\n\n const input = this.audioInputs.get(identity);\n if (input) {\n input.close();\n this.audioInputs.delete(identity);\n }\n\n this.pipeline?.removeParticipant(identity);\n }\n\n private async pipeAudioToSTT(\n input: AudioInput,\n sttStream: { sendAudio(pcm16: Buffer): void },\n identity: string,\n ): Promise<void> {\n try {\n for await (const buffer of input.frames()) {\n if (!this._running) break;\n sttStream.sendAudio(buffer);\n }\n } catch (err) {\n if (this._running) {\n log.error(`Audio pipe error for \"${identity}\":`, err);\n }\n }\n }\n}\n","import { Room, LocalAudioTrack, AudioSource, TrackSource } from '@dtelecom/server-sdk-node';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('RoomConnection');\n\nexport interface RoomConnectionOptions {\n room: string;\n apiKey: string;\n apiSecret: string;\n identity?: string;\n name?: string;\n}\n\nexport class RoomConnection {\n readonly room: Room;\n private audioSource: AudioSource | null = null;\n private localTrack: LocalAudioTrack | null = null;\n private _connected = false;\n\n constructor() {\n this.room = new Room();\n }\n\n get connected(): boolean {\n return this._connected;\n }\n\n /**\n * Connect to a dTelecom room.\n *\n * 1. Create an Ed25519 JWT via AccessToken\n * 2. Discover nearest SFU via getWsUrl()\n * 3. Connect Room via WebRTC\n * 4. Publish an audio track for the agent to speak through\n */\n async connect(options: RoomConnectionOptions): Promise<void> {\n const { room: roomName, apiKey, apiSecret, identity = 'agent', name } = options;\n\n log.info(`Connecting to room \"${roomName}\" as \"${identity}\"...`);\n\n // Dynamic import to avoid bundling server-sdk-js in the main chunk\n const { AccessToken } = await import('@dtelecom/server-sdk-js');\n\n // Create token\n const token = new AccessToken(apiKey, apiSecret, {\n identity,\n name: name ?? identity,\n });\n token.addGrant({\n roomJoin: true,\n room: roomName,\n canPublish: true,\n canSubscribe: true,\n canPublishData: true,\n });\n\n // Discover SFU\n const wsUrl = await token.getWsUrl();\n const jwt = token.toJwt();\n\n log.info(`SFU URL: ${wsUrl}`);\n\n // Connect\n await this.room.connect(wsUrl, jwt, { autoSubscribe: true });\n this._connected = true;\n\n log.info('Connected successfully');\n }\n\n /**\n * Publish an audio track so the agent can speak.\n * Returns the AudioSource to feed PCM16 audio into.\n */\n async publishAudioTrack(): Promise<AudioSource> {\n if (this.audioSource) return this.audioSource;\n\n // 48kHz mono — matches Opus/WebRTC native rate, no resampling needed\n this.audioSource = new AudioSource(48000, 1);\n this.localTrack = LocalAudioTrack.createAudioTrack('agent-voice', this.audioSource);\n\n await this.room.localParticipant.publishTrack(this.localTrack, {\n name: 'agent-voice',\n source: TrackSource.MICROPHONE,\n });\n\n log.info('Audio track published');\n return this.audioSource;\n }\n\n /** Disconnect from the room and clean up resources. */\n async disconnect(): Promise<void> {\n if (!this._connected) return;\n\n if (this.localTrack) {\n await this.room.localParticipant.unpublishTrack(this.localTrack);\n this.localTrack = null;\n }\n\n if (this.audioSource) {\n this.audioSource.destroy();\n this.audioSource = null;\n }\n\n await this.room.disconnect();\n this._connected = false;\n\n log.info('Disconnected from room');\n }\n}\n","import { RemoteAudioTrack, AudioStream, AudioFrame } from '@dtelecom/server-sdk-node';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('AudioInput');\n\nexport class AudioInput {\n readonly participantIdentity: string;\n private stream: AudioStream;\n private _closed = false;\n private frameCount = 0;\n\n constructor(track: RemoteAudioTrack, participantIdentity: string) {\n this.participantIdentity = participantIdentity;\n // 16kHz mono — standard for STT\n this.stream = track.createStream(16000, 1);\n log.info(`AudioInput created for \"${participantIdentity}\" (trackSid=${track.sid})`);\n }\n\n get closed(): boolean {\n return this._closed;\n }\n\n /**\n * Async iterate over PCM16 buffers from this participant.\n * Each yielded Buffer is 16kHz mono PCM16 LE.\n */\n async *frames(): AsyncGenerator<Buffer> {\n for await (const frame of this.stream) {\n if (this._closed) break;\n this.frameCount++;\n if (this.frameCount === 1 || this.frameCount % 500 === 0) {\n log.info(`[${this.participantIdentity}] frame #${this.frameCount}`);\n }\n yield frame.toBuffer();\n }\n log.info(`[${this.participantIdentity}] frame iterator ended (total: ${this.frameCount})`);\n }\n\n /** Async iterate over AudioFrame objects. */\n async *audioFrames(): AsyncGenerator<AudioFrame> {\n for await (const frame of this.stream) {\n if (this._closed) break;\n yield frame;\n }\n }\n\n close(): void {\n if (this._closed) return;\n this._closed = true;\n this.stream.close();\n log.debug(`AudioInput closed for participant \"${this.participantIdentity}\"`);\n }\n}\n","import { AudioSource, AudioFrame } from '@dtelecom/server-sdk-node';\nimport { writeFileSync, appendFileSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('AudioOutput');\n\n/** Rate at which we write audio (16kHz mono, 20ms frames = 320 samples) */\nconst SAMPLE_RATE = 16000;\nconst CHANNELS = 1;\nconst FRAME_DURATION_MS = 20;\nconst SAMPLES_PER_FRAME = (SAMPLE_RATE * FRAME_DURATION_MS) / 1000; // 320 at 16kHz\n\n/** Pre-allocated silence frame */\nconst SILENCE = new Int16Array(SAMPLES_PER_FRAME);\n\nexport class AudioOutput {\n private source: AudioSource;\n private _playing = false;\n private _responding = false;\n private _stopped = false;\n private silenceInterval: ReturnType<typeof setInterval> | null = null;\n\n /** When set, raw PCM from TTS is saved to this directory as WAV files for debugging. */\n dumpDir: string | null = null;\n private dumpCounter = 0;\n\n constructor(source: AudioSource) {\n this.source = source;\n }\n\n get playing(): boolean {\n return this._playing;\n }\n\n /**\n * Mark the start of a multi-sentence response.\n * Suppresses silence injection between sentences so partial frames\n * in AudioSource's buffer don't get corrupted by interleaved silence.\n */\n beginResponse(): void {\n this._responding = true;\n }\n\n /** Mark the end of a response — re-enable silence keepalive. */\n endResponse(): void {\n this._responding = false;\n }\n\n /**\n * Start sparse silence keepalive to prevent the SFU from dropping the track.\n * With Opus DTX enabled, the encoder handles silence natively — we only need\n * an occasional packet to keep the SSRC alive.\n */\n startSilence(): void {\n if (this.silenceInterval) return;\n\n log.debug('Starting silence keepalive (sparse, 3s interval)');\n\n this.silenceInterval = setInterval(() => {\n if (!this._playing && !this._responding && !this._stopped) {\n const f = new AudioFrame(SILENCE, SAMPLE_RATE, CHANNELS, SAMPLES_PER_FRAME);\n this.source.captureFrame(f).catch(() => {});\n }\n }, 3000);\n }\n\n /**\n * Write a PCM16 buffer to the audio output.\n * The buffer is split into 20ms frames and fed to AudioSource.\n */\n async writeBuffer(pcm16: Buffer): Promise<void> {\n this._playing = true;\n try {\n await this.writeFrames(pcm16);\n } finally {\n this._playing = false;\n }\n }\n\n /**\n * Write a stream of PCM16 buffers (from TTS) to the audio output.\n * Supports cancellation via AbortSignal.\n */\n async writeStream(\n stream: AsyncIterable<Buffer>,\n signal?: AbortSignal,\n ): Promise<void> {\n this._playing = true;\n const streamStart = performance.now();\n let chunkCount = 0;\n let totalBytes = 0;\n\n log.debug('writeStream: started');\n\n // Collect raw TTS chunks for WAV dump if enabled\n const rawChunks: Buffer[] | null = this.dumpDir ? [] : null;\n\n try {\n for await (const chunk of stream) {\n if (signal?.aborted) {\n log.debug(`writeStream: cancelled after ${chunkCount} chunks, ${(performance.now() - streamStart).toFixed(0)}ms`);\n break;\n }\n chunkCount++;\n totalBytes += chunk.byteLength;\n rawChunks?.push(Buffer.from(chunk));\n await this.writeFrames(chunk);\n }\n } finally {\n this._playing = false;\n const elapsed = performance.now() - streamStart;\n const audioDurationMs = (totalBytes / 2) / SAMPLE_RATE * 1000;\n log.info(\n `writeStream: done — ${chunkCount} chunks, ${totalBytes} bytes, ` +\n `audio=${audioDurationMs.toFixed(0)}ms, wall=${elapsed.toFixed(0)}ms`,\n );\n\n // Save raw TTS audio as WAV for debugging\n if (rawChunks && rawChunks.length > 0 && this.dumpDir) {\n try {\n if (!existsSync(this.dumpDir)) mkdirSync(this.dumpDir, { recursive: true });\n const filePath = join(this.dumpDir, `tts-raw-${++this.dumpCounter}.wav`);\n writeWav(filePath, rawChunks, SAMPLE_RATE);\n log.info(`writeStream: saved raw TTS to ${filePath}`);\n } catch (err) {\n log.warn('writeStream: failed to save WAV dump:', err);\n }\n }\n }\n }\n\n /**\n * Split a PCM16 buffer into 20ms frames and write them at real-time pace.\n * Partial frames at the end are sent directly — AudioSource handles\n * accumulation in its internal buffer.\n */\n private async writeFrames(pcm16: Buffer): Promise<void> {\n // Ensure aligned buffer for Int16Array.\n // ws library may deliver Buffers with odd byteOffset.\n const aligned = Buffer.alloc(pcm16.byteLength);\n pcm16.copy(aligned);\n const samples = new Int16Array(\n aligned.buffer,\n aligned.byteOffset,\n aligned.byteLength / 2,\n );\n\n let offset = 0;\n while (offset < samples.length) {\n const end = Math.min(offset + SAMPLES_PER_FRAME, samples.length);\n const frameSamples = samples.subarray(offset, end);\n\n const frame = new AudioFrame(\n frameSamples,\n SAMPLE_RATE,\n CHANNELS,\n frameSamples.length,\n );\n\n await this.source.captureFrame(frame);\n\n // Only pace full frames — partial frames don't produce an Opus packet,\n // they just accumulate in AudioSource's buffer. Sleeping for them\n // causes audio to play slower than real-time.\n if (frameSamples.length === SAMPLES_PER_FRAME) {\n await sleep(FRAME_DURATION_MS);\n }\n\n offset = end;\n }\n }\n\n /**\n * Write silence frames for the given duration.\n * Used to pad the end of a response so the last Opus frame is fully flushed\n * and the audio doesn't cut off abruptly.\n */\n async writeSilence(durationMs: number): Promise<void> {\n const frameCount = Math.ceil(durationMs / FRAME_DURATION_MS);\n for (let i = 0; i < frameCount; i++) {\n const frame = new AudioFrame(SILENCE, SAMPLE_RATE, CHANNELS, SAMPLES_PER_FRAME);\n await this.source.captureFrame(frame);\n await sleep(FRAME_DURATION_MS);\n }\n }\n\n /** Flush any buffered audio in AudioSource */\n flush(): void {\n this.source.flush();\n this._playing = false;\n }\n\n /** Stop the silence keepalive */\n stop(): void {\n this._stopped = true;\n if (this.silenceInterval) {\n clearInterval(this.silenceInterval);\n this.silenceInterval = null;\n }\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Write a WAV file header + PCM data for debugging. */\nfunction writeWav(filePath: string, pcmChunks: Buffer[], sampleRate: number): void {\n const dataSize = pcmChunks.reduce((sum, b) => sum + b.byteLength, 0);\n const header = Buffer.alloc(44);\n header.write('RIFF', 0);\n header.writeUInt32LE(36 + dataSize, 4);\n header.write('WAVE', 8);\n header.write('fmt ', 12);\n header.writeUInt32LE(16, 16); // fmt chunk size\n header.writeUInt16LE(1, 20); // PCM format\n header.writeUInt16LE(1, 22); // mono\n header.writeUInt32LE(sampleRate, 24);\n header.writeUInt32LE(sampleRate * 2, 28); // byte rate\n header.writeUInt16LE(2, 32); // block align\n header.writeUInt16LE(16, 34); // bits per sample\n header.write('data', 36);\n header.writeUInt32LE(dataSize, 40);\n\n writeFileSync(filePath, header);\n for (const chunk of pcmChunks) {\n appendFileSync(filePath, chunk);\n }\n}\n","/**\n * Pipeline — coordinates the STT -> LLM -> TTS flow.\n *\n * Uses a producer/consumer pattern:\n * - Producer: LLM tokens -> sentence splitter -> sentence queue\n * - Consumer: sentence queue -> TTS -> audio output\n * Both run concurrently so audio playback never blocks LLM consumption.\n *\n * Supports barge-in (interruption cancels both producer and consumer).\n */\n\nimport { EventEmitter } from 'events';\nimport type {\n STTPlugin,\n STTStream,\n LLMPlugin,\n TTSPlugin,\n TranscriptionResult,\n RespondMode,\n PipelineOptions,\n PipelineEvents,\n AgentState,\n} from './types';\nimport { ContextManager } from './context-manager';\nimport { SentenceSplitter } from './sentence-splitter';\nimport { TurnDetector } from './turn-detector';\nimport { BargeIn } from './barge-in';\nimport type { AudioOutput } from '../room/audio-output';\nimport type { RoomMemory } from '../memory/room-memory';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('Pipeline');\n\n/**\n * Estimated latency from AudioSource.captureFrame() to the client hearing it:\n * Opus encode → RTP → SFU → client → jitter buffer → decode.\n * We delay the \"speaking: false\" emission by this amount so the UI status\n * matches what the user actually hears.\n */\nconst AUDIO_DRAIN_MS = 800;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport class Pipeline extends EventEmitter {\n private readonly stt: STTPlugin;\n private readonly llm: LLMPlugin;\n private readonly tts: TTSPlugin | undefined;\n private readonly audioOutput: AudioOutput;\n private readonly context: ContextManager;\n private readonly turnDetector: TurnDetector;\n private readonly bargeIn: BargeIn;\n private readonly splitter: SentenceSplitter;\n private readonly respondMode: RespondMode;\n private readonly agentName: string;\n private readonly nameVariants: string[];\n private readonly beforeRespond?: (speaker: string, text: string) => boolean | Promise<boolean>;\n private readonly memory?: RoomMemory;\n\n /** Active STT streams, keyed by participant identity */\n private sttStreams = new Map<string, STTStream>();\n\n private _processing = false;\n private _running = false;\n private _agentState: AgentState = 'idle';\n /** Queued turn while current one is still processing */\n private pendingTurn: { speaker: string; text: string } | null = null;\n\n constructor(options: PipelineOptions) {\n super();\n this.stt = options.stt;\n this.llm = options.llm;\n this.tts = options.tts;\n this.audioOutput = options.audioOutput;\n this.respondMode = options.respondMode ?? 'always';\n this.agentName = (options.agentName ?? 'assistant').toLowerCase();\n this.nameVariants = (options.nameVariants ?? []).map((n) => n.toLowerCase());\n this.beforeRespond = options.beforeRespond;\n this.memory = options.memory;\n this.context = new ContextManager({\n instructions: options.instructions,\n });\n this.turnDetector = new TurnDetector({\n silenceTimeoutMs: options.silenceTimeoutMs,\n });\n this.bargeIn = new BargeIn();\n this.splitter = new SentenceSplitter();\n\n this.turnDetector.onTurnEnd = () => {};\n\n this.bargeIn.onInterrupt = () => {\n this.audioOutput.flush();\n this.splitter.reset();\n this.setAgentState('idle');\n };\n\n // Warm up LLM\n if (this.llm.warmup) {\n this.llm.warmup(options.instructions).catch((err: unknown) => {\n log.warn('LLM warmup failed:', err);\n });\n }\n\n // Warm up TTS\n if (this.tts?.warmup) {\n this.tts.warmup().catch((err: unknown) => {\n log.warn('TTS warmup failed:', err);\n });\n }\n }\n\n get processing(): boolean {\n return this._processing;\n }\n\n get running(): boolean {\n return this._running;\n }\n\n get agentState(): AgentState {\n return this._agentState;\n }\n\n private setAgentState(state: AgentState): void {\n if (this._agentState !== state) {\n this._agentState = state;\n this.emit('agentState', state);\n }\n }\n\n addParticipant(identity: string): STTStream {\n const existing = this.sttStreams.get(identity);\n if (existing) {\n existing.close();\n this.sttStreams.delete(identity);\n log.info(`Replacing STT stream for \"${identity}\"`);\n }\n\n const stream = this.stt.createStream();\n this.sttStreams.set(identity, stream);\n this._running = true;\n\n stream.on('transcription', (result) => {\n this.handleTranscription(identity, result);\n });\n\n stream.on('error', (error) => {\n log.error(`STT error for ${identity}:`, error);\n this.emit('error', error);\n });\n\n log.info(`STT stream started for participant \"${identity}\"`);\n return stream;\n }\n\n async removeParticipant(identity: string): Promise<void> {\n const stream = this.sttStreams.get(identity);\n if (stream) {\n await stream.close();\n this.sttStreams.delete(identity);\n log.info(`STT stream removed for participant \"${identity}\"`);\n }\n }\n\n async stop(): Promise<void> {\n this._running = false;\n this.turnDetector.reset();\n this.bargeIn.reset();\n this.splitter.reset();\n\n for (const [, stream] of this.sttStreams) {\n await stream.close();\n }\n this.sttStreams.clear();\n\n log.info('Pipeline stopped');\n }\n\n getContextManager(): ContextManager {\n return this.context;\n }\n\n private lastFinalAt = 0;\n private lastSttDuration = 0;\n\n private async handleTranscription(speaker: string, result: TranscriptionResult): Promise<void> {\n this.emit('transcription', { ...result, speaker });\n\n // Non-empty interim → user is speaking\n if (!result.isFinal && result.text.trim()) {\n this.setAgentState('listening');\n }\n\n if (this.audioOutput.playing && result.text.trim().length > 0) {\n this.bargeIn.trigger();\n }\n\n if (result.isFinal && result.text.trim()) {\n const text = result.text.trim();\n this.lastFinalAt = performance.now();\n this.lastSttDuration = result.sttDuration ?? 0;\n\n // Store every turn to memory (async, non-blocking)\n this.memory?.storeTurn(speaker, text, false);\n\n if (await this.shouldRespond(speaker, text)) {\n this.processTurn(speaker, text);\n } else {\n log.info(`Not responding to \"${speaker}\": \"${text.slice(0, 60)}\" (mode=${this.respondMode})`);\n this.setAgentState('idle');\n }\n } else if (result.isFinal) {\n // Empty final or no text — user stopped speaking without a usable turn\n this.setAgentState('idle');\n }\n }\n\n /**\n * Determine if the agent should respond to this turn.\n * In 'always' mode: responds to everything.\n * In 'addressed' mode: only when agent name is mentioned + optional beforeRespond hook.\n */\n private async shouldRespond(speaker: string, text: string): Promise<boolean> {\n if (this.respondMode === 'always') return true;\n\n // Check if agent name or variants are mentioned\n const lower = text.toLowerCase();\n const nameMatch = lower.includes(this.agentName) ||\n this.nameVariants.some((v) => lower.includes(v));\n\n if (!nameMatch) return false;\n\n // If beforeRespond hook exists, let it decide\n if (this.beforeRespond) {\n return this.beforeRespond(speaker, text);\n }\n\n return true;\n }\n\n private async processTurn(speaker: string, text: string): Promise<void> {\n if (this._processing) {\n log.info(`Queuing turn (current still processing): \"${text}\"`);\n this.pendingTurn = { speaker, text };\n this.bargeIn.trigger();\n return;\n }\n\n this._processing = true;\n\n // ── Latency tracking ──\n const tSpeechEnd = this.lastFinalAt;\n const sttDuration = this.lastSttDuration;\n let tLlmFirstToken = 0;\n let tFirstSentence = 0;\n let tFirstAudioPlayed = 0;\n\n log.info(`Processing turn from \"${speaker}\": ${text}`);\n\n try {\n this.context.addUserTurn(speaker, text);\n\n if (this.context.shouldSummarize()) {\n await this.context.summarize(this.llm);\n }\n\n const signal = this.bargeIn.startCycle();\n\n // Search memory for relevant past context\n let memoryContext = '';\n if (this.memory) {\n try {\n memoryContext = await this.memory.searchRelevant(text);\n } catch (err) {\n log.warn('Memory search failed:', err);\n }\n }\n\n const messages = this.context.buildMessages(memoryContext || undefined);\n let fullResponse = '';\n\n this.setAgentState('thinking');\n\n // ── Producer/Consumer pattern ──\n const sentenceQueue: string[] = [];\n let producerDone = false;\n let wakeConsumer: (() => void) | null = null;\n\n const wake = () => { wakeConsumer?.(); };\n\n // ── Producer: consume LLM stream, split into sentences ──\n const producer = async () => {\n let isFirstToken = true;\n let isFirstSentence = true;\n\n const llmStream = this.llm.chat(messages, signal);\n try {\n while (!signal.aborted) {\n const { value: chunk, done } = await llmStream.next();\n if (done || !chunk) break;\n if (signal.aborted) break;\n\n if (chunk.type === 'token' && chunk.token) {\n if (isFirstToken) {\n tLlmFirstToken = performance.now();\n isFirstToken = false;\n log.info(`llm_first_token: ${(tLlmFirstToken - tSpeechEnd).toFixed(0)}ms`);\n }\n\n fullResponse += chunk.token;\n\n const sentences = this.splitter.push(chunk.token);\n for (const sentence of sentences) {\n if (signal.aborted) break;\n if (isFirstSentence) {\n tFirstSentence = performance.now();\n isFirstSentence = false;\n log.info(`first_sentence: ${(tFirstSentence - tSpeechEnd).toFixed(0)}ms — \"${sentence.slice(0, 60)}\"`);\n }\n sentenceQueue.push(sentence);\n wake();\n }\n }\n }\n } finally {\n await llmStream.return(undefined);\n }\n\n // Flush remaining text from splitter\n if (!signal.aborted) {\n const remaining = this.splitter.flush();\n if (remaining) {\n if (isFirstSentence) {\n tFirstSentence = performance.now();\n isFirstSentence = false;\n log.info(`first_sentence (flush): ${(tFirstSentence - tSpeechEnd).toFixed(0)}ms — \"${remaining.slice(0, 60)}\"`);\n }\n sentenceQueue.push(remaining);\n wake();\n }\n }\n\n producerDone = true;\n wake();\n };\n\n // ── Consumer: synthesize sentences and play audio ──\n // beginResponse/endResponse suppresses silence injection between\n // sentences so partial frames in AudioSource don't get corrupted.\n const consumer = async () => {\n this.audioOutput.beginResponse();\n try {\n while (true) {\n if (signal.aborted) break;\n\n if (sentenceQueue.length > 0) {\n const sentence = sentenceQueue.shift()!;\n // Skip sentences with no word characters (e.g. stray quotes/punctuation)\n if (!/\\w/.test(sentence)) {\n log.debug(`Skipping non-word sentence: \"${sentence}\"`);\n continue;\n }\n await this.synthesizeAndPlay(sentence, signal, (t) => {\n if (!tFirstAudioPlayed) {\n tFirstAudioPlayed = t;\n this.setAgentState('speaking');\n }\n this.emit('sentence', sentence);\n });\n continue;\n }\n\n if (producerDone) break;\n\n // Wait for producer to push a sentence\n await new Promise<void>((resolve) => {\n wakeConsumer = resolve;\n });\n wakeConsumer = null;\n }\n } finally {\n if (!signal.aborted) {\n await this.audioOutput.writeSilence(40);\n }\n this.audioOutput.endResponse();\n }\n };\n\n await Promise.all([producer(), consumer()]);\n\n // ── Latency summary ──\n // STT: last interim (≈ end of speech) → final transcript received\n // LLM: final transcript → first complete sentence (TTFT + accumulation)\n // TTS: first sentence ready → first audio chunk to WebRTC\n // Overall: STT + LLM + TTS\n const ttftMs = tLlmFirstToken ? tLlmFirstToken - tSpeechEnd : 0;\n const llmMs = tFirstSentence ? tFirstSentence - tSpeechEnd : 0;\n const ttsMs = tFirstAudioPlayed && tFirstSentence ? tFirstAudioPlayed - tFirstSentence : 0;\n const overallMs = sttDuration + llmMs + ttsMs;\n\n log.info(\n `LATENCY \"${text.slice(0, 30)}\": ` +\n `STT=${sttDuration.toFixed(0)}ms ` +\n `LLM=${llmMs.toFixed(0)}ms (TTFT=${ttftMs.toFixed(0)}ms) ` +\n `TTS=${ttsMs.toFixed(0)}ms ` +\n `Overall=${overallMs.toFixed(0)}ms`,\n );\n\n if (fullResponse.trim()) {\n this.context.addAgentTurn(fullResponse.trim());\n this.memory?.storeTurn('assistant', fullResponse.trim(), true);\n this.emit('response', fullResponse.trim());\n }\n\n // Wait for audio pipeline to drain before signaling \"listening\"\n // (AudioSource → Opus → RTP → SFU → client decode)\n await sleep(AUDIO_DRAIN_MS);\n this.setAgentState('idle');\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'AbortError') {\n log.debug('Turn processing aborted (barge-in)');\n } else {\n log.error('Error processing turn:', err);\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n this._processing = false;\n this.bargeIn.reset();\n\n if (this.pendingTurn) {\n const { speaker: nextSpeaker, text: nextText } = this.pendingTurn;\n this.pendingTurn = null;\n log.info(`Processing queued turn from \"${nextSpeaker}\": ${nextText}`);\n this.processTurn(nextSpeaker, nextText);\n }\n }\n }\n\n /**\n * Speak text directly via TTS, bypassing the LLM.\n * Supports barge-in — if the student speaks, the greeting is cut short.\n * Adds the text to conversation context so the LLM knows what was said.\n */\n async say(text: string): Promise<void> {\n if (this._processing) {\n log.warn('say() called while processing — skipping');\n return;\n }\n\n this._processing = true;\n log.info(`say(): \"${text.slice(0, 60)}\"`);\n\n try {\n const signal = this.bargeIn.startCycle();\n this.audioOutput.beginResponse();\n this.setAgentState('thinking');\n\n await this.synthesizeAndPlay(text, signal, () => {\n this.setAgentState('speaking');\n this.emit('sentence', text);\n });\n\n if (!signal.aborted) {\n await this.audioOutput.writeSilence(40);\n this.context.addAgentTurn(text);\n this.memory?.storeTurn('assistant', text, true);\n this.emit('response', text);\n }\n\n // Wait for audio pipeline to drain before signaling \"listening\"\n await sleep(AUDIO_DRAIN_MS);\n this.setAgentState('idle');\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'AbortError') {\n log.debug('say() aborted (barge-in)');\n } else {\n log.error('Error in say():', err);\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n } finally {\n this._processing = false;\n this.audioOutput.endResponse();\n this.bargeIn.reset();\n\n if (this.pendingTurn) {\n const { speaker: nextSpeaker, text: nextText } = this.pendingTurn;\n this.pendingTurn = null;\n log.info(`Processing queued turn from \"${nextSpeaker}\": ${nextText}`);\n this.processTurn(nextSpeaker, nextText);\n }\n }\n }\n\n private async synthesizeAndPlay(\n text: string,\n signal: AbortSignal,\n onFirstAudio: (timestamp: number) => void,\n ): Promise<void> {\n if (!this.tts || signal.aborted) {\n log.info(`[Agent says]: ${text}`);\n return;\n }\n\n try {\n const ttsStart = performance.now();\n let firstChunk = true;\n let ttsChunkCount = 0;\n\n const ttsStream = this.tts.synthesize(text, signal);\n const measuredStream = async function* () {\n for await (const chunk of ttsStream) {\n ttsChunkCount++;\n if (firstChunk) {\n firstChunk = false;\n const now = performance.now();\n log.info(`tts_first_audio: ${(now - ttsStart).toFixed(0)}ms for \"${text.slice(0, 40)}\"`);\n onFirstAudio(now);\n }\n yield chunk;\n }\n };\n\n await this.audioOutput.writeStream(measuredStream(), signal);\n log.info(`synthesizeAndPlay done: ${(performance.now() - ttsStart).toFixed(0)}ms, ${ttsChunkCount} chunks for \"${text.slice(0, 40)}\"`);\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'AbortError') return;\n throw err;\n }\n }\n}\n","import type { Message, LLMPlugin } from './types';\nimport { createLogger } from '../utils/logger';\n\nconst log = createLogger('ContextManager');\n\n/** Rough token estimate: 1 token ~ 4 chars */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nexport interface ContextManagerOptions {\n /** System instructions for the agent */\n instructions: string;\n /** Max tokens before triggering summarization (default: 5000) */\n maxContextTokens?: number;\n /** Number of recent turns to keep verbatim (default: 4) */\n recentTurnsToKeep?: number;\n}\n\ninterface Turn {\n speaker: string;\n text: string;\n isAgent: boolean;\n timestamp: number;\n}\n\nexport class ContextManager {\n private readonly instructions: string;\n private readonly maxContextTokens: number;\n private readonly recentTurnsToKeep: number;\n\n private turns: Turn[] = [];\n private summary: string | null = null;\n\n constructor(options: ContextManagerOptions) {\n this.instructions = options.instructions;\n this.maxContextTokens = options.maxContextTokens ?? 5000;\n this.recentTurnsToKeep = options.recentTurnsToKeep ?? 4;\n }\n\n /** Add a user's speech turn to the conversation */\n addUserTurn(speaker: string, text: string): void {\n this.turns.push({\n speaker,\n text,\n isAgent: false,\n timestamp: Date.now(),\n });\n }\n\n /** Add the agent's response to the conversation */\n addAgentTurn(text: string): void {\n this.turns.push({\n speaker: 'assistant',\n text,\n isAgent: true,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Build the messages array for the LLM call.\n *\n * Structure:\n * [system prompt]\n * [memory context, if provided]\n * [conversation summary, if any]\n * [recent verbatim turns]\n *\n * @param memoryContext - Optional relevant context injected by the application\n */\n buildMessages(memoryContext?: string): Message[] {\n const messages: Message[] = [];\n\n // System prompt\n messages.push({ role: 'system', content: this.instructions });\n\n // Application-injected memory context (if available)\n if (memoryContext) {\n messages.push({\n role: 'system',\n content: `Relevant context from past conversations:\\n${memoryContext}`,\n });\n }\n\n // Conversation summary (if summarization has occurred)\n if (this.summary) {\n messages.push({\n role: 'system',\n content: `Conversation summary so far:\\n${this.summary}`,\n });\n }\n\n // Format turns as messages\n const turnsToInclude = this.summary\n ? this.turns.slice(-this.recentTurnsToKeep)\n : this.turns;\n\n for (const turn of turnsToInclude) {\n if (turn.isAgent) {\n messages.push({ role: 'assistant', content: turn.text });\n } else {\n messages.push({\n role: 'user',\n content: `[${turn.speaker}]: ${turn.text}`,\n });\n }\n }\n\n return messages;\n }\n\n /** Check if summarization should be triggered */\n shouldSummarize(): boolean {\n const totalTokens = this.turns.reduce(\n (acc, t) => acc + estimateTokens(t.text) + 10,\n estimateTokens(this.instructions),\n );\n return totalTokens > this.maxContextTokens;\n }\n\n /**\n * Summarize older turns using the LLM.\n * Keeps the most recent turns verbatim.\n */\n async summarize(llm: LLMPlugin): Promise<void> {\n if (this.turns.length <= this.recentTurnsToKeep) return;\n\n const olderTurns = this.turns.slice(0, -this.recentTurnsToKeep);\n const transcript = olderTurns\n .map((t) => `[${t.speaker}]: ${t.text}`)\n .join('\\n');\n\n const summaryPrompt: Message[] = [\n {\n role: 'system',\n content: 'Summarize this conversation concisely, preserving key facts, decisions, and action items.',\n },\n { role: 'user', content: transcript },\n ];\n\n let summaryText = '';\n for await (const chunk of llm.chat(summaryPrompt)) {\n if (chunk.type === 'token' && chunk.token) {\n summaryText += chunk.token;\n }\n }\n\n this.summary = this.summary\n ? `${this.summary}\\n\\n${summaryText}`\n : summaryText;\n\n this.turns = this.turns.slice(-this.recentTurnsToKeep);\n\n log.info(`Summarized ${olderTurns.length} turns, ${this.turns.length} recent turns kept`);\n }\n\n /** Get the full transcript */\n getFullTranscript(): string {\n return this.turns.map((t) => `[${t.speaker}]: ${t.text}`).join('\\n');\n }\n\n /** Reset the context */\n reset(): void {\n this.turns = [];\n this.summary = null;\n }\n}\n","/**\n * SentenceSplitter — buffers streaming LLM tokens into speakable chunks\n * for TTS synthesis.\n *\n * Split strategy:\n * 1. Sentence boundary (.!?) — always split\n * 2. Clause boundary (,;:—) — split if buffer >= MIN_CHUNK chars\n * 3. Word boundary — forced split if buffer >= MAX_CHUNK chars\n */\n\nconst MIN_CHUNK = 20;\nconst MAX_CHUNK = 150;\n\nexport class SentenceSplitter {\n private buffer = '';\n\n /** Add a token and get back any speakable chunks */\n push(token: string): string[] {\n this.buffer += token;\n return this.extractChunks();\n }\n\n /** Flush any remaining text as a final chunk */\n flush(): string | null {\n const text = this.buffer.trim();\n this.buffer = '';\n return text.length > 0 ? text : null;\n }\n\n /** Reset the splitter */\n reset(): void {\n this.buffer = '';\n }\n\n private extractChunks(): string[] {\n const chunks: string[] = [];\n\n while (true) {\n // 1. Sentence boundary (.!?) — split on complete sentences\n const sentenceMatch = this.buffer.match(/[^.!?]*[.!?]\\s*/);\n if (sentenceMatch && sentenceMatch.index !== undefined) {\n const end = sentenceMatch.index + sentenceMatch[0].length;\n const chunk = this.buffer.slice(0, end).trim();\n if (chunk.length >= MIN_CHUNK) {\n chunks.push(chunk);\n this.buffer = this.buffer.slice(end);\n continue;\n }\n }\n\n // 2. Clause boundary (,;:—) if buffer is getting long\n if (this.buffer.length >= MAX_CHUNK) {\n const clauseMatch = this.buffer.match(/[,;:\\u2014]\\s*/);\n if (clauseMatch && clauseMatch.index !== undefined && clauseMatch.index >= MIN_CHUNK) {\n const end = clauseMatch.index + clauseMatch[0].length;\n const chunk = this.buffer.slice(0, end).trim();\n chunks.push(chunk);\n this.buffer = this.buffer.slice(end);\n continue;\n }\n\n // 3. Word boundary — forced split\n const spaceIdx = this.buffer.lastIndexOf(' ', MAX_CHUNK);\n if (spaceIdx >= MIN_CHUNK) {\n const chunk = this.buffer.slice(0, spaceIdx).trim();\n chunks.push(chunk);\n this.buffer = this.buffer.slice(spaceIdx);\n continue;\n }\n }\n\n break;\n }\n\n return chunks;\n }\n}\n","import { createLogger } from '../utils/logger';\n\nconst log = createLogger('TurnDetector');\n\nexport interface TurnDetectorOptions {\n /** Silence duration after final transcription before triggering (default: 800ms) */\n silenceTimeoutMs?: number;\n}\n\nexport class TurnDetector {\n private readonly silenceTimeoutMs: number;\n private silenceTimer: ReturnType<typeof setTimeout> | null = null;\n private _onTurnEnd: (() => void) | null = null;\n private lastFinalText = '';\n\n constructor(options: TurnDetectorOptions = {}) {\n this.silenceTimeoutMs = options.silenceTimeoutMs ?? 800;\n }\n\n /** Set the callback for when a turn ends */\n set onTurnEnd(cb: (() => void) | null) {\n this._onTurnEnd = cb;\n }\n\n /**\n * Feed a transcription result.\n * Returns true if this result represents a completed turn.\n */\n handleTranscription(text: string, isFinal: boolean): boolean {\n this.clearTimer();\n\n if (isFinal && text.trim().length > 0) {\n this.lastFinalText = text;\n\n // Start silence timer — if no new speech, the turn is done\n this.silenceTimer = setTimeout(() => {\n log.debug(`Turn ended after ${this.silenceTimeoutMs}ms silence`);\n this._onTurnEnd?.();\n }, this.silenceTimeoutMs);\n\n return false;\n }\n\n if (!isFinal && text.trim().length > 0) {\n // Interim result — user is still speaking, reset timer\n this.clearTimer();\n }\n\n return false;\n }\n\n /** Force-trigger turn end */\n forceTurnEnd(): void {\n this.clearTimer();\n this._onTurnEnd?.();\n }\n\n /** Reset state */\n reset(): void {\n this.clearTimer();\n this.lastFinalText = '';\n }\n\n private clearTimer(): void {\n if (this.silenceTimer) {\n clearTimeout(this.silenceTimer);\n this.silenceTimer = null;\n }\n }\n}\n","import { createLogger } from '../utils/logger';\n\nconst log = createLogger('BargeIn');\n\nexport class BargeIn {\n private abortController: AbortController | null = null;\n private _interrupted = false;\n private _onInterrupt: (() => void) | null = null;\n\n get interrupted(): boolean {\n return this._interrupted;\n }\n\n /** Set the callback for when barge-in occurs */\n set onInterrupt(cb: (() => void) | null) {\n this._onInterrupt = cb;\n }\n\n /**\n * Create a new AbortController for the current response cycle.\n * Call this at the start of each STT->LLM->TTS cycle.\n */\n startCycle(): AbortSignal {\n this.abortController = new AbortController();\n this._interrupted = false;\n return this.abortController.signal;\n }\n\n /** Trigger barge-in. Called when STT detects speech during agent output. */\n trigger(): void {\n if (this._interrupted) return;\n this._interrupted = true;\n\n log.info('Barge-in detected — cancelling current response');\n\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n\n this._onInterrupt?.();\n }\n\n /** Reset after the interrupted cycle is cleaned up */\n reset(): void {\n this._interrupted = false;\n this.abortController = null;\n }\n}\n"],"mappings":"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","names":["EventEmitter","log","log","log","log","log","log","sleep","log","EventEmitter","RoomMemory"]}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { j as STTPlugin, k as STTStreamOptions, S as STTStream, L as LLMPlugin, M as Message, e as LLMChunk, l as TTSPlugin } from '../types-Cs5uUoTC.mjs';
|
|
2
|
+
import '@dtelecom/server-sdk-node';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* DeepgramSTT — real-time streaming STT via Deepgram WebSocket API.
|
|
6
|
+
*
|
|
7
|
+
* Protocol:
|
|
8
|
+
* - Connect to wss://api.deepgram.com/v1/listen?... with config as query params
|
|
9
|
+
* - Auth via Authorization header: "Token <apiKey>"
|
|
10
|
+
* - Send audio as binary WebSocket frames (PCM16 16kHz mono)
|
|
11
|
+
* - Receive JSON: { type: "Results", channel: { alternatives: [{ transcript }] }, is_final, speech_final }
|
|
12
|
+
* - Send KeepAlive every 5s when no audio is being sent
|
|
13
|
+
* - Send CloseStream to gracefully shut down
|
|
14
|
+
*
|
|
15
|
+
* End-of-utterance strategy:
|
|
16
|
+
* Buffer all is_final=true transcripts. Emit the buffered utterance as a
|
|
17
|
+
* single final TranscriptionResult when speech_final=true OR UtteranceEnd
|
|
18
|
+
* arrives. Interim results (is_final=false) are emitted immediately for
|
|
19
|
+
* real-time feedback.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
interface DeepgramSTTOptions {
|
|
23
|
+
apiKey: string;
|
|
24
|
+
/** Deepgram model (default: 'nova-3') */
|
|
25
|
+
model?: string;
|
|
26
|
+
/** Language code (default: 'en') */
|
|
27
|
+
language?: string;
|
|
28
|
+
/** Enable interim results (default: true) */
|
|
29
|
+
interimResults?: boolean;
|
|
30
|
+
/** Enable punctuation (default: true) */
|
|
31
|
+
punctuate?: boolean;
|
|
32
|
+
/** Endpointing in ms (default: 300). Set to false to disable. */
|
|
33
|
+
endpointing?: number | false;
|
|
34
|
+
/** Keywords to boost recognition (e.g. ['dTelecom:5', 'WebRTC:3']) */
|
|
35
|
+
keywords?: string[];
|
|
36
|
+
/** Enable smart formatting (default: false) */
|
|
37
|
+
smartFormat?: boolean;
|
|
38
|
+
/** Utterance end timeout in ms (default: 1000). Requires interimResults. */
|
|
39
|
+
utteranceEndMs?: number;
|
|
40
|
+
}
|
|
41
|
+
declare class DeepgramSTT implements STTPlugin {
|
|
42
|
+
private readonly options;
|
|
43
|
+
constructor(options: DeepgramSTTOptions);
|
|
44
|
+
createStream(options?: STTStreamOptions): STTStream;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* OpenRouterLLM — streaming LLM via OpenRouter (OpenAI-compatible API).
|
|
49
|
+
*
|
|
50
|
+
* Uses native fetch() with SSE parsing for streaming responses.
|
|
51
|
+
* No SDK dependency — just HTTP.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
interface OpenRouterLLMOptions {
|
|
55
|
+
apiKey: string;
|
|
56
|
+
/** Model identifier (e.g. 'openai/gpt-4o', 'anthropic/claude-sonnet-4') */
|
|
57
|
+
model: string;
|
|
58
|
+
/** Max tokens in response (default: 512) */
|
|
59
|
+
maxTokens?: number;
|
|
60
|
+
/** Sampling temperature 0-2 (default: 0.7) */
|
|
61
|
+
temperature?: number;
|
|
62
|
+
/** OpenRouter provider routing preferences */
|
|
63
|
+
providerRouting?: {
|
|
64
|
+
/** Sort providers by metric (e.g. 'latency') */
|
|
65
|
+
sort?: string;
|
|
66
|
+
/** Pin to specific providers in order */
|
|
67
|
+
order?: string[];
|
|
68
|
+
/** Allow fallback to other providers if pinned ones fail */
|
|
69
|
+
allowFallbacks?: boolean;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
declare class OpenRouterLLM implements LLMPlugin {
|
|
73
|
+
private readonly apiKey;
|
|
74
|
+
private readonly model;
|
|
75
|
+
private readonly maxTokens;
|
|
76
|
+
private readonly temperature;
|
|
77
|
+
private readonly provider?;
|
|
78
|
+
constructor(options: OpenRouterLLMOptions);
|
|
79
|
+
/**
|
|
80
|
+
* Warm up the LLM by sending the system prompt and a short message.
|
|
81
|
+
* Primes the HTTP/TLS connection and model loading on the provider side.
|
|
82
|
+
*/
|
|
83
|
+
warmup(systemPrompt: string): Promise<void>;
|
|
84
|
+
chat(messages: Message[], signal?: AbortSignal): AsyncGenerator<LLMChunk>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* CartesiaTTS — real-time streaming TTS via Cartesia WebSocket API.
|
|
89
|
+
*
|
|
90
|
+
* Protocol:
|
|
91
|
+
* - Connect to wss://api.cartesia.ai/tts/websocket?api_key=...&cartesia_version=...
|
|
92
|
+
* - Send JSON: { model_id, transcript, voice: { mode: "id", id }, output_format, context_id }
|
|
93
|
+
* - Receive JSON: { type: "chunk", data: "<base64 PCM>" } — audio data
|
|
94
|
+
* - Receive JSON: { type: "done", context_id } — synthesis complete
|
|
95
|
+
* - Audio is base64-encoded PCM16 LE at the requested sample rate
|
|
96
|
+
*
|
|
97
|
+
* Uses a persistent WebSocket connection to avoid per-sentence handshake overhead.
|
|
98
|
+
* Each synthesize() call uses a unique context_id for multiplexing.
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
interface CartesiaTTSOptions {
|
|
102
|
+
apiKey: string;
|
|
103
|
+
/** Cartesia voice ID */
|
|
104
|
+
voiceId: string;
|
|
105
|
+
/** Model ID (default: 'sonic-3') */
|
|
106
|
+
modelId?: string;
|
|
107
|
+
/** Output sample rate in Hz (default: 16000) */
|
|
108
|
+
sampleRate?: number;
|
|
109
|
+
/** API version (default: '2024-06-10') */
|
|
110
|
+
apiVersion?: string;
|
|
111
|
+
/** Language code (default: 'en') */
|
|
112
|
+
language?: string;
|
|
113
|
+
/** Speech speed multiplier, 0.6-1.5 (default: 1.0). Sonic-3 only. */
|
|
114
|
+
speed?: number;
|
|
115
|
+
/** Emotion string (e.g. 'friendly', 'calm'). Sonic-3 only. */
|
|
116
|
+
emotion?: string;
|
|
117
|
+
}
|
|
118
|
+
declare class CartesiaTTS implements TTSPlugin {
|
|
119
|
+
private readonly apiKey;
|
|
120
|
+
private readonly voiceId;
|
|
121
|
+
private readonly modelId;
|
|
122
|
+
private readonly sampleRate;
|
|
123
|
+
private readonly apiVersion;
|
|
124
|
+
private readonly language?;
|
|
125
|
+
private readonly speed;
|
|
126
|
+
private readonly emotion;
|
|
127
|
+
private ws;
|
|
128
|
+
private _connected;
|
|
129
|
+
private connectPromise;
|
|
130
|
+
/** Active contexts keyed by context_id */
|
|
131
|
+
private contexts;
|
|
132
|
+
private contextCounter;
|
|
133
|
+
constructor(options: CartesiaTTSOptions);
|
|
134
|
+
/** Pre-connect the WebSocket so first synthesize() doesn't pay connection cost. */
|
|
135
|
+
warmup(): Promise<void>;
|
|
136
|
+
synthesize(text: string, signal?: AbortSignal): AsyncGenerator<Buffer>;
|
|
137
|
+
/** Ensure the persistent WebSocket is connected. */
|
|
138
|
+
private ensureConnection;
|
|
139
|
+
private handleMessage;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { CartesiaTTS, type CartesiaTTSOptions, DeepgramSTT, type DeepgramSTTOptions, OpenRouterLLM, type OpenRouterLLMOptions };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { j as STTPlugin, k as STTStreamOptions, S as STTStream, L as LLMPlugin, M as Message, e as LLMChunk, l as TTSPlugin } from '../types-Cs5uUoTC.js';
|
|
2
|
+
import '@dtelecom/server-sdk-node';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* DeepgramSTT — real-time streaming STT via Deepgram WebSocket API.
|
|
6
|
+
*
|
|
7
|
+
* Protocol:
|
|
8
|
+
* - Connect to wss://api.deepgram.com/v1/listen?... with config as query params
|
|
9
|
+
* - Auth via Authorization header: "Token <apiKey>"
|
|
10
|
+
* - Send audio as binary WebSocket frames (PCM16 16kHz mono)
|
|
11
|
+
* - Receive JSON: { type: "Results", channel: { alternatives: [{ transcript }] }, is_final, speech_final }
|
|
12
|
+
* - Send KeepAlive every 5s when no audio is being sent
|
|
13
|
+
* - Send CloseStream to gracefully shut down
|
|
14
|
+
*
|
|
15
|
+
* End-of-utterance strategy:
|
|
16
|
+
* Buffer all is_final=true transcripts. Emit the buffered utterance as a
|
|
17
|
+
* single final TranscriptionResult when speech_final=true OR UtteranceEnd
|
|
18
|
+
* arrives. Interim results (is_final=false) are emitted immediately for
|
|
19
|
+
* real-time feedback.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
interface DeepgramSTTOptions {
|
|
23
|
+
apiKey: string;
|
|
24
|
+
/** Deepgram model (default: 'nova-3') */
|
|
25
|
+
model?: string;
|
|
26
|
+
/** Language code (default: 'en') */
|
|
27
|
+
language?: string;
|
|
28
|
+
/** Enable interim results (default: true) */
|
|
29
|
+
interimResults?: boolean;
|
|
30
|
+
/** Enable punctuation (default: true) */
|
|
31
|
+
punctuate?: boolean;
|
|
32
|
+
/** Endpointing in ms (default: 300). Set to false to disable. */
|
|
33
|
+
endpointing?: number | false;
|
|
34
|
+
/** Keywords to boost recognition (e.g. ['dTelecom:5', 'WebRTC:3']) */
|
|
35
|
+
keywords?: string[];
|
|
36
|
+
/** Enable smart formatting (default: false) */
|
|
37
|
+
smartFormat?: boolean;
|
|
38
|
+
/** Utterance end timeout in ms (default: 1000). Requires interimResults. */
|
|
39
|
+
utteranceEndMs?: number;
|
|
40
|
+
}
|
|
41
|
+
declare class DeepgramSTT implements STTPlugin {
|
|
42
|
+
private readonly options;
|
|
43
|
+
constructor(options: DeepgramSTTOptions);
|
|
44
|
+
createStream(options?: STTStreamOptions): STTStream;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* OpenRouterLLM — streaming LLM via OpenRouter (OpenAI-compatible API).
|
|
49
|
+
*
|
|
50
|
+
* Uses native fetch() with SSE parsing for streaming responses.
|
|
51
|
+
* No SDK dependency — just HTTP.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
interface OpenRouterLLMOptions {
|
|
55
|
+
apiKey: string;
|
|
56
|
+
/** Model identifier (e.g. 'openai/gpt-4o', 'anthropic/claude-sonnet-4') */
|
|
57
|
+
model: string;
|
|
58
|
+
/** Max tokens in response (default: 512) */
|
|
59
|
+
maxTokens?: number;
|
|
60
|
+
/** Sampling temperature 0-2 (default: 0.7) */
|
|
61
|
+
temperature?: number;
|
|
62
|
+
/** OpenRouter provider routing preferences */
|
|
63
|
+
providerRouting?: {
|
|
64
|
+
/** Sort providers by metric (e.g. 'latency') */
|
|
65
|
+
sort?: string;
|
|
66
|
+
/** Pin to specific providers in order */
|
|
67
|
+
order?: string[];
|
|
68
|
+
/** Allow fallback to other providers if pinned ones fail */
|
|
69
|
+
allowFallbacks?: boolean;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
declare class OpenRouterLLM implements LLMPlugin {
|
|
73
|
+
private readonly apiKey;
|
|
74
|
+
private readonly model;
|
|
75
|
+
private readonly maxTokens;
|
|
76
|
+
private readonly temperature;
|
|
77
|
+
private readonly provider?;
|
|
78
|
+
constructor(options: OpenRouterLLMOptions);
|
|
79
|
+
/**
|
|
80
|
+
* Warm up the LLM by sending the system prompt and a short message.
|
|
81
|
+
* Primes the HTTP/TLS connection and model loading on the provider side.
|
|
82
|
+
*/
|
|
83
|
+
warmup(systemPrompt: string): Promise<void>;
|
|
84
|
+
chat(messages: Message[], signal?: AbortSignal): AsyncGenerator<LLMChunk>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* CartesiaTTS — real-time streaming TTS via Cartesia WebSocket API.
|
|
89
|
+
*
|
|
90
|
+
* Protocol:
|
|
91
|
+
* - Connect to wss://api.cartesia.ai/tts/websocket?api_key=...&cartesia_version=...
|
|
92
|
+
* - Send JSON: { model_id, transcript, voice: { mode: "id", id }, output_format, context_id }
|
|
93
|
+
* - Receive JSON: { type: "chunk", data: "<base64 PCM>" } — audio data
|
|
94
|
+
* - Receive JSON: { type: "done", context_id } — synthesis complete
|
|
95
|
+
* - Audio is base64-encoded PCM16 LE at the requested sample rate
|
|
96
|
+
*
|
|
97
|
+
* Uses a persistent WebSocket connection to avoid per-sentence handshake overhead.
|
|
98
|
+
* Each synthesize() call uses a unique context_id for multiplexing.
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
interface CartesiaTTSOptions {
|
|
102
|
+
apiKey: string;
|
|
103
|
+
/** Cartesia voice ID */
|
|
104
|
+
voiceId: string;
|
|
105
|
+
/** Model ID (default: 'sonic-3') */
|
|
106
|
+
modelId?: string;
|
|
107
|
+
/** Output sample rate in Hz (default: 16000) */
|
|
108
|
+
sampleRate?: number;
|
|
109
|
+
/** API version (default: '2024-06-10') */
|
|
110
|
+
apiVersion?: string;
|
|
111
|
+
/** Language code (default: 'en') */
|
|
112
|
+
language?: string;
|
|
113
|
+
/** Speech speed multiplier, 0.6-1.5 (default: 1.0). Sonic-3 only. */
|
|
114
|
+
speed?: number;
|
|
115
|
+
/** Emotion string (e.g. 'friendly', 'calm'). Sonic-3 only. */
|
|
116
|
+
emotion?: string;
|
|
117
|
+
}
|
|
118
|
+
declare class CartesiaTTS implements TTSPlugin {
|
|
119
|
+
private readonly apiKey;
|
|
120
|
+
private readonly voiceId;
|
|
121
|
+
private readonly modelId;
|
|
122
|
+
private readonly sampleRate;
|
|
123
|
+
private readonly apiVersion;
|
|
124
|
+
private readonly language?;
|
|
125
|
+
private readonly speed;
|
|
126
|
+
private readonly emotion;
|
|
127
|
+
private ws;
|
|
128
|
+
private _connected;
|
|
129
|
+
private connectPromise;
|
|
130
|
+
/** Active contexts keyed by context_id */
|
|
131
|
+
private contexts;
|
|
132
|
+
private contextCounter;
|
|
133
|
+
constructor(options: CartesiaTTSOptions);
|
|
134
|
+
/** Pre-connect the WebSocket so first synthesize() doesn't pay connection cost. */
|
|
135
|
+
warmup(): Promise<void>;
|
|
136
|
+
synthesize(text: string, signal?: AbortSignal): AsyncGenerator<Buffer>;
|
|
137
|
+
/** Ensure the persistent WebSocket is connected. */
|
|
138
|
+
private ensureConnection;
|
|
139
|
+
private handleMessage;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { CartesiaTTS, type CartesiaTTSOptions, DeepgramSTT, type DeepgramSTTOptions, OpenRouterLLM, type OpenRouterLLMOptions };
|