@micdrop/server 2.0.11 → 2.0.12
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/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -415,6 +415,7 @@ var MicdropServer = class {
|
|
|
415
415
|
this.config.agent.addUserMessage(transcript);
|
|
416
416
|
if (!this.currentUserStream) {
|
|
417
417
|
this.log("User stopped speaking, answering");
|
|
418
|
+
this.cancel();
|
|
418
419
|
this.answer();
|
|
419
420
|
}
|
|
420
421
|
};
|
|
@@ -476,7 +477,6 @@ var MicdropServer = class {
|
|
|
476
477
|
this.config?.tts.cancel();
|
|
477
478
|
this.config?.agent.cancel();
|
|
478
479
|
this.operationQueue = [];
|
|
479
|
-
this.log("Operation queue cleared");
|
|
480
480
|
}
|
|
481
481
|
onMute() {
|
|
482
482
|
this.currentUserStream?.end();
|
|
@@ -499,6 +499,7 @@ var MicdropServer = class {
|
|
|
499
499
|
this.log(
|
|
500
500
|
"User stopped speaking and a transcript already exists, answering"
|
|
501
501
|
);
|
|
502
|
+
this.cancel();
|
|
502
503
|
this.answer();
|
|
503
504
|
}
|
|
504
505
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/agent/Agent.ts","../src/agent/tools.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["export * from './agent'\nexport * from './audio-convert'\nexport * from './errors'\nexport * from './Logger'\nexport * from './MicdropServer'\nexport * from './stt'\nexport * from './tts'\nexport * from './types'\nexport * from './waitForParams'\n","import { EventEmitter } from 'eventemitter3'\nimport { PassThrough, Readable, Writable } from 'stream'\nimport type { z } from 'zod'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationItem,\n MicdropConversationMessage,\n MicdropConversationToolCall,\n MicdropConversationToolResult,\n MicdropToolCall,\n} from '../types'\nimport {\n AUTO_END_CALL_PROMPT,\n AUTO_END_CALL_TOOL_NAME,\n AUTO_IGNORE_USER_NOISE_PROMPT,\n AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n AUTO_SEMANTIC_TURN_PROMPT,\n AUTO_SEMANTIC_TURN_TOOL_NAME,\n Tool,\n} from './tools'\n\nexport interface AgentOptions {\n systemPrompt: string\n\n // Enable auto ending of the call when user asks to end the call\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoEndCall?: boolean | string\n\n // Enable detection of an incomplete sentence, and skip the answer (assistant waits)\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoSemanticTurn?: boolean | string\n\n // Ignore of the last user message when it's meaningless\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoIgnoreUserNoise?: boolean | string\n\n // Extract a value from the answer\n // Value must be at the end of the answer, in JSON or between tags\n extract?: ExtractJsonOptions | ExtractTagOptions\n\n // Function called before any answer is generated\n // Return true to skip generation\n onBeforeAnswer?: (\n this: Agent,\n stream: Writable\n ) => void | boolean | Promise<boolean>\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationItem]\n CancelLastUserMessage: []\n SkipAnswer: []\n EndCall: []\n ToolCall: [MicdropToolCall]\n}\n\nexport interface ExtractOptions {\n callback?: (value: string) => void\n saveInMetadata?: boolean\n}\n\nexport interface ExtractJsonOptions extends ExtractOptions {\n json: true\n callback?: (value: any) => void\n}\n\nexport interface ExtractTagOptions extends ExtractOptions {\n startTag: string\n endTag: string\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n public conversation: MicdropConversation\n\n protected tools: Tool[]\n protected answerCount = 0\n protected answering = false\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n this.tools = this.getDefaultTools()\n }\n\n protected abstract generateAnswer(stream: PassThrough): Promise<void>\n abstract cancel(): void\n\n answer(): Readable {\n this.log('Start answering')\n const answerCount = ++this.answerCount\n const stream = new PassThrough()\n this.answering = true\n\n Promise.resolve()\n // Call hook onBeforeAnswer\n .then(() => this.options.onBeforeAnswer?.bind(this)(stream))\n // Generate answer (if not skipped)\n .then((skip) => {\n if (skip) return\n return this.generateAnswer(stream)\n })\n // End stream\n .finally(() => {\n if (stream.writable) {\n stream.end()\n }\n if (answerCount === this.answerCount) {\n this.answering = false\n }\n })\n\n return stream\n }\n\n addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n addTool<Schema extends z.ZodObject>(tool: Tool<Schema>) {\n this.tools.push(tool)\n }\n\n removeTool(name: string) {\n const index = this.tools.findIndex((tool) => tool.name === name)\n if (index !== -1) {\n this.tools.splice(index, 1)\n }\n }\n\n getTool(name: string): Tool | undefined {\n return this.tools.find((tool) => tool.name === name)\n }\n\n addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n addToolMessage(\n message: MicdropConversationToolCall | MicdropConversationToolResult\n ) {\n this.log('Adding tool message:', message)\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessageIndex = this.conversation.findLastIndex(\n (message) => message.role === 'user'\n )\n if (lastMessageIndex !== -1) {\n this.conversation.splice(lastMessageIndex, 1)\n }\n this.emit('CancelLastUserMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected getDefaultTools() {\n const tools: Tool[] = []\n if (this.options.autoEndCall) {\n tools.push({\n name: AUTO_END_CALL_TOOL_NAME,\n description:\n typeof this.options.autoEndCall === 'string'\n ? this.options.autoEndCall\n : AUTO_END_CALL_PROMPT,\n execute: () => this.endCall(),\n })\n }\n if (this.options.autoSemanticTurn) {\n tools.push({\n name: AUTO_SEMANTIC_TURN_TOOL_NAME,\n description:\n typeof this.options.autoSemanticTurn === 'string'\n ? this.options.autoSemanticTurn\n : AUTO_SEMANTIC_TURN_PROMPT,\n skipAnswer: true,\n execute: () => this.skipAnswer(),\n })\n }\n if (this.options.autoIgnoreUserNoise) {\n tools.push({\n name: AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n description:\n typeof this.options.autoIgnoreUserNoise === 'string'\n ? this.options.autoIgnoreUserNoise\n : AUTO_IGNORE_USER_NOISE_PROMPT,\n skipAnswer: true,\n execute: () => this.cancelLastUserMessage(),\n })\n }\n return tools\n }\n\n protected async executeTool(toolCall: MicdropConversationToolCall) {\n try {\n const tool = this.getTool(toolCall.toolName)\n if (!tool) {\n throw new Error(`Tool not found \"${toolCall.toolName}\"`)\n }\n\n this.log('Executing tool:', toolCall.toolName, toolCall.parameters)\n\n // Save tool call in conversation\n this.addToolMessage(toolCall)\n\n const parameters = JSON.parse(toolCall.parameters)\n const output = tool.execute ? await tool.execute(parameters) : {}\n\n // Save tool result in conversation\n this.addToolMessage({\n role: 'tool_result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: JSON.stringify(output ?? null),\n })\n\n // Emit output\n if (tool.emitOutput) {\n this.emit('ToolCall', {\n name: toolCall.toolName,\n parameters,\n output,\n })\n }\n\n return {\n output,\n skipAnswer: tool.skipAnswer,\n }\n } catch (error: any) {\n console.error('[OpenaiAgent] Error executing tool:', error)\n return {\n output: {\n error: error.message,\n },\n }\n }\n }\n\n protected getExtractOptions(): ExtractTagOptions | undefined {\n const extract = this.options.extract\n if (!extract) return undefined\n if ('json' in extract && extract.json) {\n return { ...extract, startTag: '{', endTag: '}' }\n }\n if ('startTag' in extract && 'endTag' in extract) {\n return extract\n }\n return undefined\n }\n\n public extract(message: string) {\n const extractOptions = this.getExtractOptions()\n let metadata: MicdropAnswerMetadata | undefined = undefined\n\n // Extract value?\n if (extractOptions) {\n const startTagIndex = message.indexOf(extractOptions.startTag)\n if (startTagIndex !== -1) {\n // Find end tag\n let endTagIndex = message.lastIndexOf(extractOptions.endTag)\n if (endTagIndex === -1) endTagIndex = message.length + 1\n else endTagIndex += extractOptions.endTag.length\n const extractedText = message.slice(startTagIndex, endTagIndex).trim()\n\n // Parse extracted value\n try {\n const extractedValue =\n 'json' in extractOptions && extractOptions.json\n ? JSON.parse(extractedText)\n : extractedText\n\n // Call callback\n if (extractOptions.callback) {\n extractOptions.callback(extractedValue)\n }\n\n // Save in metadata\n if (extractOptions.saveInMetadata) {\n metadata = { extracted: extractedValue }\n }\n } catch (error) {\n console.error(\n `[OpenaiAgent] Error parsing extracted value (${extractedText}):`,\n error\n )\n }\n\n // Remove extracted value from message\n message = message.slice(0, startTagIndex).trimEnd()\n }\n }\n return { message, metadata }\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import type { z } from 'zod'\n\nexport interface Tool<Schema extends z.ZodObject = z.ZodObject> {\n name: string\n description: string\n inputSchema?: Schema\n execute?: (input: z.infer<Schema>) => any | Promise<any>\n skipAnswer?: boolean\n emitOutput?: boolean\n}\n\nexport const AUTO_END_CALL_TOOL_NAME = 'end_call'\nexport const AUTO_END_CALL_PROMPT =\n 'Call this tool only if user asks to end the call'\n\nexport const AUTO_SEMANTIC_TURN_TOOL_NAME = 'semantic_turn'\nexport const AUTO_SEMANTIC_TURN_PROMPT =\n 'Call this tool only if last user message is obviously an incomplete sentence that you need to wait for the end before answering'\n\nexport const AUTO_IGNORE_USER_NOISE_TOOL_NAME = 'ignore_user_noise'\nexport const AUTO_IGNORE_USER_NOISE_PROMPT =\n 'Call this tool only if last user message is just an interjection or a sound that expresses emotion, hesitation, or reaction (ex: \"Uh\", \"Ahem\", \"Hmm\", \"Ah\") but doesn\\'t carry any clear meaning like agreeing, refusing, or commanding'\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n protected async generateAnswer(stream: PassThrough): Promise<void> {\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport type { Agent } from './agent'\nimport { Logger } from './Logger'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\nimport {\n MicdropCallSummary,\n MicdropClientCommands,\n MicdropConversationItem,\n MicdropServerCommands,\n} from './types'\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n private lastMessageSpeeched?: MicdropConversationItem\n\n // Queue system for operations\n private operationQueue: Array<() => Promise<void>> = []\n private isProcessingQueue = false\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n this.config.agent.on('ToolCall', (toolCall) =>\n this.socket?.send(\n `${MicdropServerCommands.ToolCall} ${JSON.stringify(toolCall)}`\n )\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private async processQueue() {\n if (this.isProcessingQueue || this.operationQueue.length === 0) return\n\n this.isProcessingQueue = true\n\n while (this.operationQueue.length > 0) {\n const operation = this.operationQueue.shift()\n if (operation) {\n try {\n await operation()\n } catch (error) {\n this.log('Error processing queued operation:', error)\n }\n }\n }\n\n this.isProcessingQueue = false\n }\n\n private queueOperation(operation: () => Promise<void>) {\n this.operationQueue.push(operation)\n this.processQueue()\n }\n\n public cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n // Clear the queue\n this.operationQueue = []\n this.log('Operation queue cleared')\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n const lastMessage = conversation?.[conversation.length - 1]\n if (\n lastMessage?.role === 'user' &&\n this.lastMessageSpeeched !== lastMessage\n ) {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.answer()\n }\n }\n\n private sendFirstMessage() {\n if (!this.config) return\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n public answer() {\n this.queueOperation(async () => {\n await this._answer()\n })\n }\n\n private async _answer() {\n if (!this.config) return\n\n // Prevent answering twice\n const lastMessage =\n this.config.agent.conversation[this.config.agent.conversation.length - 1]\n if (this.lastMessageSpeeched === lastMessage) {\n this.log('Already answered, skipping')\n return\n }\n this.lastMessageSpeeched = lastMessage\n\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this._speak(stream)\n } catch (error) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n throw error\n }\n }\n\n // Run text-to-speech and send to client\n public speak(message: string | Readable) {\n this.queueOperation(async () => {\n await this._speak(message)\n })\n }\n\n private async _speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this._sendAudio(audio)\n }\n\n public sendAudio(audio: Readable) {\n this.queueOperation(async () => {\n await this._sendAudio(audio)\n })\n }\n\n private async _sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Wait for audio stream to complete\n await new Promise<void>((resolve, reject) => {\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n reject(error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n resolve()\n })\n })\n }\n}\n","export enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n ToolCall = 'ToolCall',\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversationItem =\n | MicdropConversationMessage\n | MicdropConversationToolCall\n | MicdropConversationToolResult\n\nexport type MicdropConversation = Array<MicdropConversationItem>\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport interface MicdropConversationToolCall {\n role: 'tool_call'\n toolCallId: string\n toolName: string\n parameters: string\n}\n\nexport interface MicdropConversationToolResult {\n role: 'tool_result'\n toolCallId: string\n toolName: string\n output: string\n}\n\nexport interface MicdropToolCall {\n name: string\n parameters: any\n output: any\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":"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","names":["import_stream","ffmpeg","ffmpegInstaller","MicdropErrorCode","import_stream","MicdropClientCommands","MicdropServerCommands","import_eventemitter3","import_stream"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/agent/Agent.ts","../src/agent/tools.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["export * from './agent'\nexport * from './audio-convert'\nexport * from './errors'\nexport * from './Logger'\nexport * from './MicdropServer'\nexport * from './stt'\nexport * from './tts'\nexport * from './types'\nexport * from './waitForParams'\n","import { EventEmitter } from 'eventemitter3'\nimport { PassThrough, Readable, Writable } from 'stream'\nimport type { z } from 'zod'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationItem,\n MicdropConversationMessage,\n MicdropConversationToolCall,\n MicdropConversationToolResult,\n MicdropToolCall,\n} from '../types'\nimport {\n AUTO_END_CALL_PROMPT,\n AUTO_END_CALL_TOOL_NAME,\n AUTO_IGNORE_USER_NOISE_PROMPT,\n AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n AUTO_SEMANTIC_TURN_PROMPT,\n AUTO_SEMANTIC_TURN_TOOL_NAME,\n Tool,\n} from './tools'\n\nexport interface AgentOptions {\n systemPrompt: string\n\n // Enable auto ending of the call when user asks to end the call\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoEndCall?: boolean | string\n\n // Enable detection of an incomplete sentence, and skip the answer (assistant waits)\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoSemanticTurn?: boolean | string\n\n // Ignore of the last user message when it's meaningless\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoIgnoreUserNoise?: boolean | string\n\n // Extract a value from the answer\n // Value must be at the end of the answer, in JSON or between tags\n extract?: ExtractJsonOptions | ExtractTagOptions\n\n // Function called before any answer is generated\n // Return true to skip generation\n onBeforeAnswer?: (\n this: Agent,\n stream: Writable\n ) => void | boolean | Promise<boolean>\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationItem]\n CancelLastUserMessage: []\n SkipAnswer: []\n EndCall: []\n ToolCall: [MicdropToolCall]\n}\n\nexport interface ExtractOptions {\n callback?: (value: string) => void\n saveInMetadata?: boolean\n}\n\nexport interface ExtractJsonOptions extends ExtractOptions {\n json: true\n callback?: (value: any) => void\n}\n\nexport interface ExtractTagOptions extends ExtractOptions {\n startTag: string\n endTag: string\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n public conversation: MicdropConversation\n\n protected tools: Tool[]\n protected answerCount = 0\n protected answering = false\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n this.tools = this.getDefaultTools()\n }\n\n protected abstract generateAnswer(stream: PassThrough): Promise<void>\n abstract cancel(): void\n\n answer(): Readable {\n this.log('Start answering')\n const answerCount = ++this.answerCount\n const stream = new PassThrough()\n this.answering = true\n\n Promise.resolve()\n // Call hook onBeforeAnswer\n .then(() => this.options.onBeforeAnswer?.bind(this)(stream))\n // Generate answer (if not skipped)\n .then((skip) => {\n if (skip) return\n return this.generateAnswer(stream)\n })\n // End stream\n .finally(() => {\n if (stream.writable) {\n stream.end()\n }\n if (answerCount === this.answerCount) {\n this.answering = false\n }\n })\n\n return stream\n }\n\n addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n addTool<Schema extends z.ZodObject>(tool: Tool<Schema>) {\n this.tools.push(tool)\n }\n\n removeTool(name: string) {\n const index = this.tools.findIndex((tool) => tool.name === name)\n if (index !== -1) {\n this.tools.splice(index, 1)\n }\n }\n\n getTool(name: string): Tool | undefined {\n return this.tools.find((tool) => tool.name === name)\n }\n\n addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n addToolMessage(\n message: MicdropConversationToolCall | MicdropConversationToolResult\n ) {\n this.log('Adding tool message:', message)\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessageIndex = this.conversation.findLastIndex(\n (message) => message.role === 'user'\n )\n if (lastMessageIndex !== -1) {\n this.conversation.splice(lastMessageIndex, 1)\n }\n this.emit('CancelLastUserMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected getDefaultTools() {\n const tools: Tool[] = []\n if (this.options.autoEndCall) {\n tools.push({\n name: AUTO_END_CALL_TOOL_NAME,\n description:\n typeof this.options.autoEndCall === 'string'\n ? this.options.autoEndCall\n : AUTO_END_CALL_PROMPT,\n execute: () => this.endCall(),\n })\n }\n if (this.options.autoSemanticTurn) {\n tools.push({\n name: AUTO_SEMANTIC_TURN_TOOL_NAME,\n description:\n typeof this.options.autoSemanticTurn === 'string'\n ? this.options.autoSemanticTurn\n : AUTO_SEMANTIC_TURN_PROMPT,\n skipAnswer: true,\n execute: () => this.skipAnswer(),\n })\n }\n if (this.options.autoIgnoreUserNoise) {\n tools.push({\n name: AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n description:\n typeof this.options.autoIgnoreUserNoise === 'string'\n ? this.options.autoIgnoreUserNoise\n : AUTO_IGNORE_USER_NOISE_PROMPT,\n skipAnswer: true,\n execute: () => this.cancelLastUserMessage(),\n })\n }\n return tools\n }\n\n protected async executeTool(toolCall: MicdropConversationToolCall) {\n try {\n const tool = this.getTool(toolCall.toolName)\n if (!tool) {\n throw new Error(`Tool not found \"${toolCall.toolName}\"`)\n }\n\n this.log('Executing tool:', toolCall.toolName, toolCall.parameters)\n\n // Save tool call in conversation\n this.addToolMessage(toolCall)\n\n const parameters = JSON.parse(toolCall.parameters)\n const output = tool.execute ? await tool.execute(parameters) : {}\n\n // Save tool result in conversation\n this.addToolMessage({\n role: 'tool_result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: JSON.stringify(output ?? null),\n })\n\n // Emit output\n if (tool.emitOutput) {\n this.emit('ToolCall', {\n name: toolCall.toolName,\n parameters,\n output,\n })\n }\n\n return {\n output,\n skipAnswer: tool.skipAnswer,\n }\n } catch (error: any) {\n console.error('[OpenaiAgent] Error executing tool:', error)\n return {\n output: {\n error: error.message,\n },\n }\n }\n }\n\n protected getExtractOptions(): ExtractTagOptions | undefined {\n const extract = this.options.extract\n if (!extract) return undefined\n if ('json' in extract && extract.json) {\n return { ...extract, startTag: '{', endTag: '}' }\n }\n if ('startTag' in extract && 'endTag' in extract) {\n return extract\n }\n return undefined\n }\n\n public extract(message: string) {\n const extractOptions = this.getExtractOptions()\n let metadata: MicdropAnswerMetadata | undefined = undefined\n\n // Extract value?\n if (extractOptions) {\n const startTagIndex = message.indexOf(extractOptions.startTag)\n if (startTagIndex !== -1) {\n // Find end tag\n let endTagIndex = message.lastIndexOf(extractOptions.endTag)\n if (endTagIndex === -1) endTagIndex = message.length + 1\n else endTagIndex += extractOptions.endTag.length\n const extractedText = message.slice(startTagIndex, endTagIndex).trim()\n\n // Parse extracted value\n try {\n const extractedValue =\n 'json' in extractOptions && extractOptions.json\n ? JSON.parse(extractedText)\n : extractedText\n\n // Call callback\n if (extractOptions.callback) {\n extractOptions.callback(extractedValue)\n }\n\n // Save in metadata\n if (extractOptions.saveInMetadata) {\n metadata = { extracted: extractedValue }\n }\n } catch (error) {\n console.error(\n `[OpenaiAgent] Error parsing extracted value (${extractedText}):`,\n error\n )\n }\n\n // Remove extracted value from message\n message = message.slice(0, startTagIndex).trimEnd()\n }\n }\n return { message, metadata }\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import type { z } from 'zod'\n\nexport interface Tool<Schema extends z.ZodObject = z.ZodObject> {\n name: string\n description: string\n inputSchema?: Schema\n execute?: (input: z.infer<Schema>) => any | Promise<any>\n skipAnswer?: boolean\n emitOutput?: boolean\n}\n\nexport const AUTO_END_CALL_TOOL_NAME = 'end_call'\nexport const AUTO_END_CALL_PROMPT =\n 'Call this tool only if user asks to end the call'\n\nexport const AUTO_SEMANTIC_TURN_TOOL_NAME = 'semantic_turn'\nexport const AUTO_SEMANTIC_TURN_PROMPT =\n 'Call this tool only if last user message is obviously an incomplete sentence that you need to wait for the end before answering'\n\nexport const AUTO_IGNORE_USER_NOISE_TOOL_NAME = 'ignore_user_noise'\nexport const AUTO_IGNORE_USER_NOISE_PROMPT =\n 'Call this tool only if last user message is just an interjection or a sound that expresses emotion, hesitation, or reaction (ex: \"Uh\", \"Ahem\", \"Hmm\", \"Ah\") but doesn\\'t carry any clear meaning like agreeing, refusing, or commanding'\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n protected async generateAnswer(stream: PassThrough): Promise<void> {\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport type { Agent } from './agent'\nimport { Logger } from './Logger'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\nimport {\n MicdropCallSummary,\n MicdropClientCommands,\n MicdropConversationItem,\n MicdropServerCommands,\n} from './types'\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n private lastMessageSpeeched?: MicdropConversationItem\n\n // Queue system for operations\n private operationQueue: Array<() => Promise<void>> = []\n private isProcessingQueue = false\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n this.config.agent.on('ToolCall', (toolCall) =>\n this.socket?.send(\n `${MicdropServerCommands.ToolCall} ${JSON.stringify(toolCall)}`\n )\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private async processQueue() {\n if (this.isProcessingQueue || this.operationQueue.length === 0) return\n\n this.isProcessingQueue = true\n\n while (this.operationQueue.length > 0) {\n const operation = this.operationQueue.shift()\n if (operation) {\n try {\n await operation()\n } catch (error) {\n this.log('Error processing queued operation:', error)\n }\n }\n }\n\n this.isProcessingQueue = false\n }\n\n private queueOperation(operation: () => Promise<void>) {\n this.operationQueue.push(operation)\n this.processQueue()\n }\n\n public cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n // Clear the queue\n this.operationQueue = []\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n const lastMessage = conversation?.[conversation.length - 1]\n if (\n lastMessage?.role === 'user' &&\n this.lastMessageSpeeched !== lastMessage\n ) {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.cancel()\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.cancel()\n this.answer()\n }\n }\n\n private sendFirstMessage() {\n if (!this.config) return\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n public answer() {\n this.queueOperation(async () => {\n await this._answer()\n })\n }\n\n private async _answer() {\n if (!this.config) return\n\n // Prevent answering twice\n const lastMessage =\n this.config.agent.conversation[this.config.agent.conversation.length - 1]\n if (this.lastMessageSpeeched === lastMessage) {\n this.log('Already answered, skipping')\n return\n }\n this.lastMessageSpeeched = lastMessage\n\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this._speak(stream)\n } catch (error) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n throw error\n }\n }\n\n // Run text-to-speech and send to client\n public speak(message: string | Readable) {\n this.queueOperation(async () => {\n await this._speak(message)\n })\n }\n\n private async _speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this._sendAudio(audio)\n }\n\n public sendAudio(audio: Readable) {\n this.queueOperation(async () => {\n await this._sendAudio(audio)\n })\n }\n\n private async _sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Wait for audio stream to complete\n await new Promise<void>((resolve, reject) => {\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n reject(error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n resolve()\n })\n })\n }\n}\n","export enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n ToolCall = 'ToolCall',\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversationItem =\n | MicdropConversationMessage\n | MicdropConversationToolCall\n | MicdropConversationToolResult\n\nexport type MicdropConversation = Array<MicdropConversationItem>\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport interface MicdropConversationToolCall {\n role: 'tool_call'\n toolCallId: string\n toolName: string\n parameters: string\n}\n\nexport interface MicdropConversationToolResult {\n role: 'tool_result'\n toolCallId: string\n toolName: string\n output: string\n}\n\nexport interface MicdropToolCall {\n name: string\n parameters: any\n output: any\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,2BAA6B;AAC7B,oBAAgD;;;ACUzC,IAAM,0BAA0B;AAChC,IAAM,uBACX;AAEK,IAAM,+BAA+B;AACrC,IAAM,4BACX;AAEK,IAAM,mCAAmC;AACzC,IAAM,gCACX;;;ADoDK,IAAe,QAAf,cAEG,kCAA0B;AAAA,EAQlC,YAAsB,SAAkB;AACtC,UAAM;AADc;AAHtB,SAAU,cAAc;AACxB,SAAU,YAAY;AAIpB,SAAK,eAAe,CAAC,EAAE,MAAM,UAAU,SAAS,QAAQ,aAAa,CAAC;AACtE,SAAK,QAAQ,KAAK,gBAAgB;AAAA,EACpC;AAAA,EAKA,SAAmB;AACjB,SAAK,IAAI,iBAAiB;AAC1B,UAAM,cAAc,EAAE,KAAK;AAC3B,UAAM,SAAS,IAAI,0BAAY;AAC/B,SAAK,YAAY;AAEjB,YAAQ,QAAQ,EAEb,KAAK,MAAM,KAAK,QAAQ,gBAAgB,KAAK,IAAI,EAAE,MAAM,CAAC,EAE1D,KAAK,CAAC,SAAS;AACd,UAAI,KAAM;AACV,aAAO,KAAK,eAAe,MAAM;AAAA,IACnC,CAAC,EAEA,QAAQ,MAAM;AACb,UAAI,OAAO,UAAU;AACnB,eAAO,IAAI;AAAA,MACb;AACA,UAAI,gBAAgB,KAAK,aAAa;AACpC,aAAK,YAAY;AAAA,MACnB;AAAA,IACF,CAAC;AAEH,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,MAAc,UAAkC;AAC7D,SAAK,WAAW,QAAQ,MAAM,QAAQ;AAAA,EACxC;AAAA,EAEA,oBAAoB,MAAc,UAAkC;AAClE,SAAK,WAAW,aAAa,MAAM,QAAQ;AAAA,EAC7C;AAAA,EAEA,QAAoC,MAAoB;AACtD,SAAK,MAAM,KAAK,IAAI;AAAA,EACtB;AAAA,EAEA,WAAW,MAAc;AACvB,UAAM,QAAQ,KAAK,MAAM,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI;AAC/D,QAAI,UAAU,IAAI;AAChB,WAAK,MAAM,OAAO,OAAO,CAAC;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,QAAQ,MAAgC;AACtC,WAAO,KAAK,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI;AAAA,EACrD;AAAA,EAEA,WACE,MACA,MACA,UACA;AACA,SAAK,IAAI,UAAU,IAAI,6BAA6B,IAAI,EAAE;AAC1D,UAAM,UAAsC;AAAA,MAC1C;AAAA,MACA,SAAS;AAAA,MACT;AAAA,IACF;AACA,SAAK,aAAa,KAAK,OAAO;AAC9B,SAAK,KAAK,WAAW,OAAO;AAAA,EAC9B;AAAA,EAEA,eACE,SACA;AACA,SAAK,IAAI,wBAAwB,OAAO;AACxC,SAAK,aAAa,KAAK,OAAO;AAC9B,SAAK,KAAK,WAAW,OAAO;AAAA,EAC9B;AAAA,EAEU,UAAU;AAClB,SAAK,IAAI,aAAa;AACtB,SAAK,KAAK,SAAS;AAAA,EACrB;AAAA,EAEU,wBAAwB;AAChC,SAAK,IAAI,8BAA8B;AACvC,UAAM,mBAAmB,KAAK,aAAa;AAAA,MACzC,CAAC,YAAY,QAAQ,SAAS;AAAA,IAChC;AACA,QAAI,qBAAqB,IAAI;AAC3B,WAAK,aAAa,OAAO,kBAAkB,CAAC;AAAA,IAC9C;AACA,SAAK,KAAK,uBAAuB;AAAA,EACnC;AAAA,EAEU,aAAa;AACrB,SAAK,IAAI,iBAAiB;AAC1B,SAAK,KAAK,YAAY;AAAA,EACxB;AAAA,EAEU,kBAAkB;AAC1B,UAAM,QAAgB,CAAC;AACvB,QAAI,KAAK,QAAQ,aAAa;AAC5B,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,aACE,OAAO,KAAK,QAAQ,gBAAgB,WAChC,KAAK,QAAQ,cACb;AAAA,QACN,SAAS,MAAM,KAAK,QAAQ;AAAA,MAC9B,CAAC;AAAA,IACH;AACA,QAAI,KAAK,QAAQ,kBAAkB;AACjC,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,aACE,OAAO,KAAK,QAAQ,qBAAqB,WACrC,KAAK,QAAQ,mBACb;AAAA,QACN,YAAY;AAAA,QACZ,SAAS,MAAM,KAAK,WAAW;AAAA,MACjC,CAAC;AAAA,IACH;AACA,QAAI,KAAK,QAAQ,qBAAqB;AACpC,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,aACE,OAAO,KAAK,QAAQ,wBAAwB,WACxC,KAAK,QAAQ,sBACb;AAAA,QACN,YAAY;AAAA,QACZ,SAAS,MAAM,KAAK,sBAAsB;AAAA,MAC5C,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAgB,YAAY,UAAuC;AACjE,QAAI;AACF,YAAM,OAAO,KAAK,QAAQ,SAAS,QAAQ;AAC3C,UAAI,CAAC,MAAM;AACT,cAAM,IAAI,MAAM,mBAAmB,SAAS,QAAQ,GAAG;AAAA,MACzD;AAEA,WAAK,IAAI,mBAAmB,SAAS,UAAU,SAAS,UAAU;AAGlE,WAAK,eAAe,QAAQ;AAE5B,YAAM,aAAa,KAAK,MAAM,SAAS,UAAU;AACjD,YAAM,SAAS,KAAK,UAAU,MAAM,KAAK,QAAQ,UAAU,IAAI,CAAC;AAGhE,WAAK,eAAe;AAAA,QAClB,MAAM;AAAA,QACN,YAAY,SAAS;AAAA,QACrB,UAAU,SAAS;AAAA,QACnB,QAAQ,KAAK,UAAU,UAAU,IAAI;AAAA,MACvC,CAAC;AAGD,UAAI,KAAK,YAAY;AACnB,aAAK,KAAK,YAAY;AAAA,UACpB,MAAM,SAAS;AAAA,UACf;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL;AAAA,QACA,YAAY,KAAK;AAAA,MACnB;AAAA,IACF,SAAS,OAAY;AACnB,cAAQ,MAAM,uCAAuC,KAAK;AAC1D,aAAO;AAAA,QACL,QAAQ;AAAA,UACN,OAAO,MAAM;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEU,oBAAmD;AAC3D,UAAM,UAAU,KAAK,QAAQ;AAC7B,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI,UAAU,WAAW,QAAQ,MAAM;AACrC,aAAO,EAAE,GAAG,SAAS,UAAU,KAAK,QAAQ,IAAI;AAAA,IAClD;AACA,QAAI,cAAc,WAAW,YAAY,SAAS;AAChD,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEO,QAAQ,SAAiB;AAC9B,UAAM,iBAAiB,KAAK,kBAAkB;AAC9C,QAAI,WAA8C;AAGlD,QAAI,gBAAgB;AAClB,YAAM,gBAAgB,QAAQ,QAAQ,eAAe,QAAQ;AAC7D,UAAI,kBAAkB,IAAI;AAExB,YAAI,cAAc,QAAQ,YAAY,eAAe,MAAM;AAC3D,YAAI,gBAAgB,GAAI,eAAc,QAAQ,SAAS;AAAA,YAClD,gBAAe,eAAe,OAAO;AAC1C,cAAM,gBAAgB,QAAQ,MAAM,eAAe,WAAW,EAAE,KAAK;AAGrE,YAAI;AACF,gBAAM,iBACJ,UAAU,kBAAkB,eAAe,OACvC,KAAK,MAAM,aAAa,IACxB;AAGN,cAAI,eAAe,UAAU;AAC3B,2BAAe,SAAS,cAAc;AAAA,UACxC;AAGA,cAAI,eAAe,gBAAgB;AACjC,uBAAW,EAAE,WAAW,eAAe;AAAA,UACzC;AAAA,QACF,SAAS,OAAO;AACd,kBAAQ;AAAA,YACN,gDAAgD,aAAa;AAAA,YAC7D;AAAA,UACF;AAAA,QACF;AAGA,kBAAU,QAAQ,MAAM,GAAG,aAAa,EAAE,QAAQ;AAAA,MACpD;AAAA,IACF;AACA,WAAO,EAAE,SAAS,SAAS;AAAA,EAC7B;AAAA,EAEU,OAAO,SAAgB;AAC/B,SAAK,QAAQ,IAAI,GAAG,OAAO;AAAA,EAC7B;AAAA,EAEA,UAAU;AACR,SAAK,IAAI,WAAW;AACpB,SAAK,mBAAmB;AACxB,SAAK,OAAO;AAAA,EACd;AACF;;;AE3UO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAGnC,cAAc;AACZ,UAAM,EAAE,cAAc,GAAG,CAAC;AAH5B,SAAQ,IAAI;AAAA,EAIZ;AAAA,EAEA,MAAgB,eAAe,QAAoC;AACjE,UAAM,UAAU,qBAAqB,KAAK,GAAG;AAC7C,SAAK,oBAAoB,OAAO;AAChC,WAAO,MAAM,OAAO;AAAA,EACtB;AAAA,EAEA,SAAS;AAAA,EAAC;AACZ;;;ACjBA,oBAA4B;AAC5B,2BAAmB;AACnB,IAAAA,iBAAsC;AAGtC,qBAAAC,QAAO,cAAc,cAAAC,QAAgB,IAAI;AAGlC,SAAS,aACd,aACA,aAAa,MACb,WAAW,IACX;AACA,QAAM,YAAY,IAAI,2BAAY;AAClC,2BAAAD,SAAO,WAAW,EACf,cAAc,CAAC,EACf,eAAe,UAAU,EACzB,WAAW,QAAQ,QAAQ,IAAI,EAC/B,OAAO,IAAI,QAAQ,IAAI,EACvB,GAAG,SAAS,CAAC,UAAU;AACtB,YAAQ,MAAM,kCAAkC,MAAM,OAAO;AAAA,EAC/D,CAAC,EACA,KAAK,SAAS;AACjB,SAAO;AACT;AAGO,SAAS,cAAc,aAAuB,aAAa,MAAO;AACvE,QAAM,aAAa,IAAI,2BAAY;AACnC,mBAAa,qBAAAA,SAAO,WAAW,GAAG,UAAU,EAAE,KAAK,UAAU;AAC7D,SAAO;AACT;AAGO,SAAS,iBAAiB,aAAuB,aAAa,MAAO;AAC1E,QAAM,aAAa,IAAI,2BAAY;AACnC,mBAAa,qBAAAA,SAAO,WAAW,GAAG,UAAU,EACzC,YAAY,OAAO,EACnB,aAAa,CAAC,YAAY,aAAa,OAAO,CAAC,EAC/C,KAAK,UAAU;AAClB,SAAO;AACT;AAEA,SAAS,aAAa,eAAqC,aAAa,MAAO;AAC7E,SAAO,cACJ,cAAc,CAAC,EACf,eAAe,UAAU,EACzB,WAAW,SAAS,EACpB,OAAO,MAAM,EACb,cAAc;AAAA,IACb;AAAA,IACA;AAAA,IACA,OAAO,UAAU;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC,EACA,GAAG,SAAS,CAAC,UAAU;AACtB,YAAQ,MAAM,8BAA8B,MAAM,OAAO;AAAA,EAC3D,CAAC;AACL;;;AC1DO,IAAK,mBAAL,kBAAKE,sBAAL;AACL,EAAAA,oCAAA,gBAAa,QAAb;AACA,EAAAA,oCAAA,kBAAe,QAAf;AACA,EAAAA,oCAAA,cAAW,QAAX;AAHU,SAAAA;AAAA,GAAA;AAML,IAAM,eAAN,cAA2B,MAAM;AAAA,EAGtC,YAAY,MAAc,SAAiB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,YAAY,QAAmB,OAAgB;AAC7D,MAAI,iBAAiB,cAAc;AACjC,WAAO,MAAM,MAAM,MAAM,MAAM,OAAO;AAAA,EACxC,OAAO;AACL,YAAQ,MAAM,KAAK;AACnB,WAAO,MAAM,IAAI;AAAA,EACnB;AACA,SAAO,UAAU;AACnB;;;ACzBO,IAAM,SAAN,MAAa;AAAA,EAClB,YAA6B,MAAc;AAAd;AAAA,EAAe;AAAA,EAE5C,OAAO,SAAgB;AACrB,UAAM,OAAO,QAAQ,OAAO,EAAE,QAAQ,CAAC;AACvC,YAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG,OAAO;AAAA,EAClD;AACF;;;ACPA,IAAAC,iBAA8C;;;ACAvC,IAAK,wBAAL,kBAAKC,2BAAL;AACL,EAAAA,uBAAA,mBAAgB;AAChB,EAAAA,uBAAA,kBAAe;AACf,EAAAA,uBAAA,UAAO;AAHG,SAAAA;AAAA,GAAA;AAML,IAAK,wBAAL,kBAAKC,2BAAL;AACL,EAAAA,uBAAA,aAAU;AACV,EAAAA,uBAAA,2BAAwB;AACxB,EAAAA,uBAAA,gBAAa;AACb,EAAAA,uBAAA,aAAU;AACV,EAAAA,uBAAA,cAAW;AALD,SAAAA;AAAA,GAAA;;;ADgBL,IAAM,gBAAN,MAAoB;AAAA,EAezB,YAAY,QAAmB,QAAuB;AAdtD,SAAO,SAA2B;AAClC,SAAO,SAA+B;AAGtC,SAAQ,YAAY,KAAK,IAAI;AAI7B;AAAA,SAAQ,iBAA6C,CAAC;AACtD,SAAQ,oBAAoB;AA6E5B,SAAQ,UAAU,MAAM;AACtB,UAAI,CAAC,KAAK,OAAQ;AAClB,WAAK,IAAI,mBAAmB;AAC5B,YAAM,WAAW,KAAK,OAAO,KAAK,IAAI,IAAI,KAAK,aAAa,GAAI;AAGhE,WAAK,OAAO,MAAM,QAAQ;AAC1B,WAAK,OAAO,IAAI,QAAQ;AACxB,WAAK,OAAO,IAAI,QAAQ;AAGxB,WAAK,OAAO,QAAQ;AAAA,QAClB,cAAc,KAAK,OAAO,MAAM,aAAa,MAAM,CAAC;AAAA;AAAA,QACpD;AAAA,MACF,CAAC;AAGD,WAAK,SAAS;AACd,WAAK,SAAS;AAAA,IAChB;AAEA,SAAQ,YAAY,OAAO,YAAoB;AAC7C,UAAI,QAAQ,eAAe,EAAG;AAC9B,UAAI,CAAC,OAAO,SAAS,OAAO,GAAG;AAC7B,aAAK,IAAI,yBAAyB;AAClC;AAAA,MACF;AAGA,UAAI,QAAQ,aAAa,IAAI;AAC3B,cAAM,MAAM,QAAQ,SAAS;AAC7B,aAAK,IAAI,YAAY,GAAG,EAAE;AAE1B,YAAI,6CAA6C;AAE/C,eAAK,gBAAgB;AAAA,QACvB,WAAW,2BAAoC;AAE7C,eAAK,OAAO;AAAA,QACd,WAAW,2CAA4C;AAErD,eAAK,eAAe;AAAA,QACtB;AAAA,MACF,WAGS,KAAK,mBAAmB;AAC/B,aAAK,IAAI,mBAAmB,QAAQ,UAAU,SAAS;AACvD,aAAK,kBAAkB,MAAM,OAAO;AAAA,MACtC;AAAA,IACF;AAkCA,SAAQ,eAAe,OAAO,eAAuB;AACnD,UAAI,CAAC,KAAK,OAAQ;AAClB,WAAK,IAAI,qBAAqB,UAAU,GAAG;AAC3C,WAAK,OAAO,MAAM,eAAe,UAAU;AAG3C,UAAI,CAAC,KAAK,mBAAmB;AAC3B,aAAK,IAAI,kCAAkC;AAC3C,aAAK,OAAO;AACZ,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAtKE,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,IAAI,cAAc;AAGvB,SAAK,OAAO,IAAI,GAAG,cAAc,KAAK,YAAY;AAGlD,SAAK,OAAO,MAAM;AAAA,MAAG;AAAA,MAAW,CAAC,YAC/B,KAAK,QAAQ;AAAA,QACX,0BAAgC,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,MAC7D;AAAA,IACF;AACA,SAAK,OAAO,MAAM;AAAA,MAAG;AAAA,MAAyB,MAC5C,KAAK,QAAQ,wDAAgD;AAAA,IAC/D;AACA,SAAK,OAAO,MAAM;AAAA,MAAG;AAAA,MAAc,MACjC,KAAK,QAAQ,kCAAqC;AAAA,IACpD;AACA,SAAK,OAAO,MAAM;AAAA,MAAG;AAAA,MAAW,MAC9B,KAAK,QAAQ,4BAAkC;AAAA,IACjD;AACA,SAAK,OAAO,MAAM;AAAA,MAAG;AAAA,MAAY,CAAC,aAChC,KAAK,QAAQ;AAAA,QACX,4BAAiC,IAAI,KAAK,UAAU,QAAQ,CAAC;AAAA,MAC/D;AAAA,IACF;AAGA,SAAK,iBAAiB;AAGtB,WAAO,GAAG,SAAS,KAAK,OAAO;AAC/B,WAAO,GAAG,WAAW,KAAK,SAAS;AAAA,EACrC;AAAA,EAEQ,OAAO,SAAgB;AAC7B,SAAK,QAAQ,IAAI,GAAG,OAAO;AAAA,EAC7B;AAAA,EAEA,MAAc,eAAe;AAC3B,QAAI,KAAK,qBAAqB,KAAK,eAAe,WAAW,EAAG;AAEhE,SAAK,oBAAoB;AAEzB,WAAO,KAAK,eAAe,SAAS,GAAG;AACrC,YAAM,YAAY,KAAK,eAAe,MAAM;AAC5C,UAAI,WAAW;AACb,YAAI;AACF,gBAAM,UAAU;AAAA,QAClB,SAAS,OAAO;AACd,eAAK,IAAI,sCAAsC,KAAK;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAEA,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEQ,eAAe,WAAgC;AACrD,SAAK,eAAe,KAAK,SAAS;AAClC,SAAK,aAAa;AAAA,EACpB;AAAA,EAEO,SAAS;AACd,SAAK,QAAQ,IAAI,OAAO;AACxB,SAAK,QAAQ,MAAM,OAAO;AAE1B,SAAK,iBAAiB,CAAC;AAAA,EACzB;AAAA,EAsDQ,SAAS;AACf,SAAK,mBAAmB,IAAI;AAC5B,SAAK,oBAAoB;AACzB,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,kBAAkB;AACxB,QAAI,CAAC,KAAK,OAAQ;AAClB,SAAK,mBAAmB,IAAI;AAC5B,SAAK,oBAAoB,IAAI,2BAAY;AACzC,SAAK,OAAO,IAAI,WAAW,KAAK,iBAAiB;AACjD,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,iBAAiB;AACvB,SAAK,mBAAmB,IAAI;AAC5B,SAAK,oBAAoB;AAEzB,UAAM,eAAe,KAAK,QAAQ,MAAM;AACxC,UAAM,cAAc,eAAe,aAAa,SAAS,CAAC;AAC1D,QACE,aAAa,SAAS,UACtB,KAAK,wBAAwB,aAC7B;AACA,WAAK;AAAA,QACH;AAAA,MACF;AACA,WAAK,OAAO;AACZ,WAAK,OAAO;AAAA,IACd;AAAA,EACF;AAAA,EAeQ,mBAAmB;AACzB,QAAI,CAAC,KAAK,OAAQ;AAClB,QAAI,KAAK,OAAO,cAAc;AAE5B,WAAK,OAAO,MAAM,oBAAoB,KAAK,OAAO,YAAY;AAC9D,WAAK,MAAM,KAAK,OAAO,YAAY;AAAA,IACrC,WAAW,KAAK,OAAO,sBAAsB;AAE3C,WAAK,OAAO;AAAA,IACd,OAAO;AAGL,WAAK,QAAQ,kCAAqC;AAAA,IACpD;AAAA,EACF;AAAA,EAEO,SAAS;AACd,SAAK,eAAe,YAAY;AAC9B,YAAM,KAAK,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,UAAU;AACtB,QAAI,CAAC,KAAK,OAAQ;AAGlB,UAAM,cACJ,KAAK,OAAO,MAAM,aAAa,KAAK,OAAO,MAAM,aAAa,SAAS,CAAC;AAC1E,QAAI,KAAK,wBAAwB,aAAa;AAC5C,WAAK,IAAI,4BAA4B;AACrC;AAAA,IACF;AACA,SAAK,sBAAsB;AAE3B,QAAI;AAEF,YAAM,SAAS,KAAK,OAAO,MAAM,OAAO;AAGxC,YAAM,KAAK,OAAO,MAAM;AAAA,IAC1B,SAAS,OAAO;AACd,WAAK,QAAQ,kCAAqC;AAClD,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGO,MAAM,SAA4B;AACvC,SAAK,eAAe,YAAY;AAC9B,YAAM,KAAK,OAAO,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,OAAO,SAA4B;AAC/C,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,OAAQ;AAGlC,QAAI;AACJ,QAAI,OAAO,YAAY,UAAU;AAC/B,YAAM,SAAS,IAAI,2BAAY;AAC/B,aAAO,MAAM,OAAO;AACpB,aAAO,IAAI;AACX,mBAAa;AAAA,IACf,OAAO;AACL,mBAAa;AAAA,IACf;AAGA,UAAM,QAAQ,KAAK,OAAO,IAAI,MAAM,UAAU;AAG9C,UAAM,KAAK,WAAW,KAAK;AAAA,EAC7B;AAAA,EAEO,UAAU,OAAiB;AAChC,SAAK,eAAe,YAAY;AAC9B,YAAM,KAAK,WAAW,KAAK;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,WAAW,OAAiB;AACxC,QAAI,CAAC,KAAK,OAAQ;AAClB,QAAI,CAAC,MAAM,UAAU;AACnB,WAAK,IAAI,gCAAgC,KAAK;AAC9C;AAAA,IACF;AAGA,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,YAAM,GAAG,QAAQ,CAAC,UAAU;AAC1B,aAAK,IAAI,qBAAqB,MAAM,UAAU,SAAS;AACvD,aAAK,QAAQ,KAAK,KAAK;AAAA,MACzB,CAAC;AACD,YAAM,GAAG,SAAS,CAAC,UAAU;AAC3B,aAAK,IAAI,yBAAyB,KAAK;AACvC,eAAO,KAAK;AAAA,MACd,CAAC;AACD,YAAM,GAAG,OAAO,MAAM;AACpB,aAAK,IAAI,oBAAoB;AAC7B,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;;;AErTA,IAAAC,wBAA6B;AAK7B,IAAM,yBAAyB;AAAA,EAC7B,aAAa;AAAA,EACb,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;AAAA,EACd,aAAa;AAAA,EACb,cAAc;AAChB;AAMO,IAAe,MAAf,cAA2B,mCAAwB;AAAA;AAAA,EAKxD,WAAW,aAAuB;AAEhC,gBAAY,KAAK,QAAQ,CAAC,UAAU;AAClC,WAAK,WAAW,KAAK,eAAe,KAAK;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA,EAEU,OAAO,SAAgB;AAC/B,SAAK,QAAQ,IAAI,GAAG,OAAO;AAAA,EAC7B;AAAA,EAEA,UAAU;AACR,SAAK,IAAI,WAAW;AACpB,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,IAAc,YAAoB;AAChC,WAAQ,KAAK,YAAY,uBAAuB,KAAK,QAAQ,KAAM;AAAA,EACrE;AAAA,EAEQ,eACN,OACqC;AACrC,QAAI,CAAC,SAAS,MAAM,eAAe,GAAG;AACpC,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AAEA,UAAM,MAAM,IAAI,WAAW,KAAK;AAGhC,QACE,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,OACX,IAAI,CAAC,MAAM,KACX;AACA,aAAO;AAAA,IACT;AAEA,QACE,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,OACX,IAAI,CAAC,MAAM,OACX,IAAI,CAAC,MAAM,IACX;AACA,aAAO;AAAA,IACT;AAEA,QACE,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,MACX,IAAI,EAAE,MAAM,MACZ,IAAI,EAAE,MAAM,IACZ;AACA,aAAO;AAAA,IACT;AAEA,QAAI,IAAI,CAAC,MAAM,MAAQ,IAAI,CAAC,MAAM,MAAQ,IAAI,CAAC,MAAM,IAAM;AACzD,aAAO;AAAA,IACT;AAEA,QACE,IAAI,CAAC,MAAM,OACX,IAAI,CAAC,MAAM,OACX,IAAI,CAAC,MAAM,OACX,IAAI,CAAC,MAAM,KACX;AACA,aAAO;AAAA,IACT;AAEA,QACE,IAAI,CAAC,MAAM,OACX,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,MACX,IAAI,CAAC,MAAM,IACX;AACA,aAAO;AAAA,IACT;AACA,SAAK,IAAI,6CAA6C,KAAK;AAC3D,WAAO;AAAA,EACT;AACF;;;ACrGO,IAAe,UAAf,cAA+B,IAAI;AAAA,EAGxC,WAAW,aAAuB;AAChC,UAAM,WAAW,WAAW;AAG5B,SAAK,IAAI,8BAA8B;AAEvC,UAAM,SAAmB,CAAC;AAC1B,gBAAY,GAAG,QAAQ,CAAC,UAAU;AAChC,aAAO,KAAK,KAAK;AAAA,IACnB,CAAC;AAED,gBAAY,GAAG,OAAO,YAAY;AAChC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,cAAc,OAAO,OAAO,MAAM;AACxC,YAAM,OAAO,IAAI,KAAK,CAAC,WAAW,GAAG,SAAS,KAAK,SAAS,IAAI;AAAA,QAC9D,MAAM,KAAK;AAAA,MACb,CAAC;AAGD,WAAK,IAAI,sBAAsB;AAC/B,YAAM,aAAa,MAAM,KAAK,eAAe,IAAI;AACjD,WAAK,KAAK,cAAc,UAAU;AAAA,IACpC,CAAC;AAAA,EACH;AACF;;;AChCO,IAAM,UAAN,cAAsB,QAAQ;AAAA,EAA9B;AAAA;AACL,SAAQ,IAAI;AAAA;AAAA,EAEZ,MAAM,eAAe,MAAY;AAC/B,WAAO,gBAAgB,KAAK,GAAG;AAAA,EACjC;AACF;;;ACRA,SAAoB;AACpB,IAAAC,iBAAsC;;;ACE/B,IAAe,MAAf,MAAmB;AAAA,EAMd,OAAO,SAAgB;AAC/B,SAAK,QAAQ,IAAI,GAAG,OAAO;AAAA,EAC7B;AAAA,EAEA,UAAU;AACR,SAAK,IAAI,WAAW;AACpB,SAAK,OAAO;AAAA,EACd;AACF;;;ADbO,IAAM,UAAN,cAAsB,IAAI;AAAA,EAC/B,YAAoB,gBAA0B;AAC5C,UAAM;AADY;AAAA,EAEpB;AAAA,EAEA,MAAM,YAAsB;AAC1B,UAAM,cAAc,IAAI,2BAAY;AACpC,eAAW,KAAK,QAAQ,YAAY;AAClC,iBAAW,YAAY,KAAK,gBAAgB;AAC1C,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AACvD,cAAM,cAAiB,gBAAa,QAAQ;AAC5C,aAAK,IAAI,iBAAiB,YAAY,MAAM,SAAS;AACrD,oBAAY,MAAM,WAAW;AAAA,MAC/B;AACA,kBAAY,IAAI;AAAA,IAClB,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,SAAS;AAAA,EAAC;AACZ;;;AErBA,eAAsB,cACpB,QACA,UACqB;AACrB,SAAO,IAAI,QAAoB,CAAC,SAAS,WAAW;AAElD,UAAM,UAAU,WAAW,MAAM;AAC/B,aAAO,IAAI,oCAA0C,gBAAgB,CAAC;AAAA,IACxE,GAAG,GAAI;AAEP,UAAM,WAAW,CAAC,YAAoB;AAEpC,mBAAa,OAAO;AACpB,aAAO,IAAI,WAAW,QAAQ;AAE9B,UAAI;AAEF,cAAM,SAAS,SAAS,KAAK,MAAM,OAAO,CAAC;AAC3C,gBAAQ,MAAM;AAAA,MAChB,SAAS,OAAO;AACd,eAAO,IAAI,oCAA0C,gBAAgB,CAAC;AAAA,MACxE;AAAA,IACF;AAGA,WAAO,GAAG,WAAW,QAAQ;AAAA,EAC/B,CAAC;AACH;","names":["import_stream","ffmpeg","ffmpegInstaller","MicdropErrorCode","import_stream","MicdropClientCommands","MicdropServerCommands","import_eventemitter3","import_stream"]}
|
package/dist/index.mjs
CHANGED
|
@@ -356,6 +356,7 @@ var MicdropServer = class {
|
|
|
356
356
|
this.config.agent.addUserMessage(transcript);
|
|
357
357
|
if (!this.currentUserStream) {
|
|
358
358
|
this.log("User stopped speaking, answering");
|
|
359
|
+
this.cancel();
|
|
359
360
|
this.answer();
|
|
360
361
|
}
|
|
361
362
|
};
|
|
@@ -417,7 +418,6 @@ var MicdropServer = class {
|
|
|
417
418
|
this.config?.tts.cancel();
|
|
418
419
|
this.config?.agent.cancel();
|
|
419
420
|
this.operationQueue = [];
|
|
420
|
-
this.log("Operation queue cleared");
|
|
421
421
|
}
|
|
422
422
|
onMute() {
|
|
423
423
|
this.currentUserStream?.end();
|
|
@@ -440,6 +440,7 @@ var MicdropServer = class {
|
|
|
440
440
|
this.log(
|
|
441
441
|
"User stopped speaking and a transcript already exists, answering"
|
|
442
442
|
);
|
|
443
|
+
this.cancel();
|
|
443
444
|
this.answer();
|
|
444
445
|
}
|
|
445
446
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent/Agent.ts","../src/agent/tools.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["import { EventEmitter } from 'eventemitter3'\nimport { PassThrough, Readable, Writable } from 'stream'\nimport type { z } from 'zod'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationItem,\n MicdropConversationMessage,\n MicdropConversationToolCall,\n MicdropConversationToolResult,\n MicdropToolCall,\n} from '../types'\nimport {\n AUTO_END_CALL_PROMPT,\n AUTO_END_CALL_TOOL_NAME,\n AUTO_IGNORE_USER_NOISE_PROMPT,\n AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n AUTO_SEMANTIC_TURN_PROMPT,\n AUTO_SEMANTIC_TURN_TOOL_NAME,\n Tool,\n} from './tools'\n\nexport interface AgentOptions {\n systemPrompt: string\n\n // Enable auto ending of the call when user asks to end the call\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoEndCall?: boolean | string\n\n // Enable detection of an incomplete sentence, and skip the answer (assistant waits)\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoSemanticTurn?: boolean | string\n\n // Ignore of the last user message when it's meaningless\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoIgnoreUserNoise?: boolean | string\n\n // Extract a value from the answer\n // Value must be at the end of the answer, in JSON or between tags\n extract?: ExtractJsonOptions | ExtractTagOptions\n\n // Function called before any answer is generated\n // Return true to skip generation\n onBeforeAnswer?: (\n this: Agent,\n stream: Writable\n ) => void | boolean | Promise<boolean>\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationItem]\n CancelLastUserMessage: []\n SkipAnswer: []\n EndCall: []\n ToolCall: [MicdropToolCall]\n}\n\nexport interface ExtractOptions {\n callback?: (value: string) => void\n saveInMetadata?: boolean\n}\n\nexport interface ExtractJsonOptions extends ExtractOptions {\n json: true\n callback?: (value: any) => void\n}\n\nexport interface ExtractTagOptions extends ExtractOptions {\n startTag: string\n endTag: string\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n public conversation: MicdropConversation\n\n protected tools: Tool[]\n protected answerCount = 0\n protected answering = false\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n this.tools = this.getDefaultTools()\n }\n\n protected abstract generateAnswer(stream: PassThrough): Promise<void>\n abstract cancel(): void\n\n answer(): Readable {\n this.log('Start answering')\n const answerCount = ++this.answerCount\n const stream = new PassThrough()\n this.answering = true\n\n Promise.resolve()\n // Call hook onBeforeAnswer\n .then(() => this.options.onBeforeAnswer?.bind(this)(stream))\n // Generate answer (if not skipped)\n .then((skip) => {\n if (skip) return\n return this.generateAnswer(stream)\n })\n // End stream\n .finally(() => {\n if (stream.writable) {\n stream.end()\n }\n if (answerCount === this.answerCount) {\n this.answering = false\n }\n })\n\n return stream\n }\n\n addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n addTool<Schema extends z.ZodObject>(tool: Tool<Schema>) {\n this.tools.push(tool)\n }\n\n removeTool(name: string) {\n const index = this.tools.findIndex((tool) => tool.name === name)\n if (index !== -1) {\n this.tools.splice(index, 1)\n }\n }\n\n getTool(name: string): Tool | undefined {\n return this.tools.find((tool) => tool.name === name)\n }\n\n addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n addToolMessage(\n message: MicdropConversationToolCall | MicdropConversationToolResult\n ) {\n this.log('Adding tool message:', message)\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessageIndex = this.conversation.findLastIndex(\n (message) => message.role === 'user'\n )\n if (lastMessageIndex !== -1) {\n this.conversation.splice(lastMessageIndex, 1)\n }\n this.emit('CancelLastUserMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected getDefaultTools() {\n const tools: Tool[] = []\n if (this.options.autoEndCall) {\n tools.push({\n name: AUTO_END_CALL_TOOL_NAME,\n description:\n typeof this.options.autoEndCall === 'string'\n ? this.options.autoEndCall\n : AUTO_END_CALL_PROMPT,\n execute: () => this.endCall(),\n })\n }\n if (this.options.autoSemanticTurn) {\n tools.push({\n name: AUTO_SEMANTIC_TURN_TOOL_NAME,\n description:\n typeof this.options.autoSemanticTurn === 'string'\n ? this.options.autoSemanticTurn\n : AUTO_SEMANTIC_TURN_PROMPT,\n skipAnswer: true,\n execute: () => this.skipAnswer(),\n })\n }\n if (this.options.autoIgnoreUserNoise) {\n tools.push({\n name: AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n description:\n typeof this.options.autoIgnoreUserNoise === 'string'\n ? this.options.autoIgnoreUserNoise\n : AUTO_IGNORE_USER_NOISE_PROMPT,\n skipAnswer: true,\n execute: () => this.cancelLastUserMessage(),\n })\n }\n return tools\n }\n\n protected async executeTool(toolCall: MicdropConversationToolCall) {\n try {\n const tool = this.getTool(toolCall.toolName)\n if (!tool) {\n throw new Error(`Tool not found \"${toolCall.toolName}\"`)\n }\n\n this.log('Executing tool:', toolCall.toolName, toolCall.parameters)\n\n // Save tool call in conversation\n this.addToolMessage(toolCall)\n\n const parameters = JSON.parse(toolCall.parameters)\n const output = tool.execute ? await tool.execute(parameters) : {}\n\n // Save tool result in conversation\n this.addToolMessage({\n role: 'tool_result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: JSON.stringify(output ?? null),\n })\n\n // Emit output\n if (tool.emitOutput) {\n this.emit('ToolCall', {\n name: toolCall.toolName,\n parameters,\n output,\n })\n }\n\n return {\n output,\n skipAnswer: tool.skipAnswer,\n }\n } catch (error: any) {\n console.error('[OpenaiAgent] Error executing tool:', error)\n return {\n output: {\n error: error.message,\n },\n }\n }\n }\n\n protected getExtractOptions(): ExtractTagOptions | undefined {\n const extract = this.options.extract\n if (!extract) return undefined\n if ('json' in extract && extract.json) {\n return { ...extract, startTag: '{', endTag: '}' }\n }\n if ('startTag' in extract && 'endTag' in extract) {\n return extract\n }\n return undefined\n }\n\n public extract(message: string) {\n const extractOptions = this.getExtractOptions()\n let metadata: MicdropAnswerMetadata | undefined = undefined\n\n // Extract value?\n if (extractOptions) {\n const startTagIndex = message.indexOf(extractOptions.startTag)\n if (startTagIndex !== -1) {\n // Find end tag\n let endTagIndex = message.lastIndexOf(extractOptions.endTag)\n if (endTagIndex === -1) endTagIndex = message.length + 1\n else endTagIndex += extractOptions.endTag.length\n const extractedText = message.slice(startTagIndex, endTagIndex).trim()\n\n // Parse extracted value\n try {\n const extractedValue =\n 'json' in extractOptions && extractOptions.json\n ? JSON.parse(extractedText)\n : extractedText\n\n // Call callback\n if (extractOptions.callback) {\n extractOptions.callback(extractedValue)\n }\n\n // Save in metadata\n if (extractOptions.saveInMetadata) {\n metadata = { extracted: extractedValue }\n }\n } catch (error) {\n console.error(\n `[OpenaiAgent] Error parsing extracted value (${extractedText}):`,\n error\n )\n }\n\n // Remove extracted value from message\n message = message.slice(0, startTagIndex).trimEnd()\n }\n }\n return { message, metadata }\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import type { z } from 'zod'\n\nexport interface Tool<Schema extends z.ZodObject = z.ZodObject> {\n name: string\n description: string\n inputSchema?: Schema\n execute?: (input: z.infer<Schema>) => any | Promise<any>\n skipAnswer?: boolean\n emitOutput?: boolean\n}\n\nexport const AUTO_END_CALL_TOOL_NAME = 'end_call'\nexport const AUTO_END_CALL_PROMPT =\n 'Call this tool only if user asks to end the call'\n\nexport const AUTO_SEMANTIC_TURN_TOOL_NAME = 'semantic_turn'\nexport const AUTO_SEMANTIC_TURN_PROMPT =\n 'Call this tool only if last user message is obviously an incomplete sentence that you need to wait for the end before answering'\n\nexport const AUTO_IGNORE_USER_NOISE_TOOL_NAME = 'ignore_user_noise'\nexport const AUTO_IGNORE_USER_NOISE_PROMPT =\n 'Call this tool only if last user message is just an interjection or a sound that expresses emotion, hesitation, or reaction (ex: \"Uh\", \"Ahem\", \"Hmm\", \"Ah\") but doesn\\'t carry any clear meaning like agreeing, refusing, or commanding'\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n protected async generateAnswer(stream: PassThrough): Promise<void> {\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport type { Agent } from './agent'\nimport { Logger } from './Logger'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\nimport {\n MicdropCallSummary,\n MicdropClientCommands,\n MicdropConversationItem,\n MicdropServerCommands,\n} from './types'\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n private lastMessageSpeeched?: MicdropConversationItem\n\n // Queue system for operations\n private operationQueue: Array<() => Promise<void>> = []\n private isProcessingQueue = false\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n this.config.agent.on('ToolCall', (toolCall) =>\n this.socket?.send(\n `${MicdropServerCommands.ToolCall} ${JSON.stringify(toolCall)}`\n )\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private async processQueue() {\n if (this.isProcessingQueue || this.operationQueue.length === 0) return\n\n this.isProcessingQueue = true\n\n while (this.operationQueue.length > 0) {\n const operation = this.operationQueue.shift()\n if (operation) {\n try {\n await operation()\n } catch (error) {\n this.log('Error processing queued operation:', error)\n }\n }\n }\n\n this.isProcessingQueue = false\n }\n\n private queueOperation(operation: () => Promise<void>) {\n this.operationQueue.push(operation)\n this.processQueue()\n }\n\n public cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n // Clear the queue\n this.operationQueue = []\n this.log('Operation queue cleared')\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n const lastMessage = conversation?.[conversation.length - 1]\n if (\n lastMessage?.role === 'user' &&\n this.lastMessageSpeeched !== lastMessage\n ) {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.answer()\n }\n }\n\n private sendFirstMessage() {\n if (!this.config) return\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n public answer() {\n this.queueOperation(async () => {\n await this._answer()\n })\n }\n\n private async _answer() {\n if (!this.config) return\n\n // Prevent answering twice\n const lastMessage =\n this.config.agent.conversation[this.config.agent.conversation.length - 1]\n if (this.lastMessageSpeeched === lastMessage) {\n this.log('Already answered, skipping')\n return\n }\n this.lastMessageSpeeched = lastMessage\n\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this._speak(stream)\n } catch (error) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n throw error\n }\n }\n\n // Run text-to-speech and send to client\n public speak(message: string | Readable) {\n this.queueOperation(async () => {\n await this._speak(message)\n })\n }\n\n private async _speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this._sendAudio(audio)\n }\n\n public sendAudio(audio: Readable) {\n this.queueOperation(async () => {\n await this._sendAudio(audio)\n })\n }\n\n private async _sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Wait for audio stream to complete\n await new Promise<void>((resolve, reject) => {\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n reject(error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n resolve()\n })\n })\n }\n}\n","export enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n ToolCall = 'ToolCall',\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversationItem =\n | MicdropConversationMessage\n | MicdropConversationToolCall\n | MicdropConversationToolResult\n\nexport type MicdropConversation = Array<MicdropConversationItem>\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport interface MicdropConversationToolCall {\n role: 'tool_call'\n toolCallId: string\n toolName: string\n parameters: string\n}\n\nexport interface MicdropConversationToolResult {\n role: 'tool_result'\n toolCallId: string\n toolName: string\n output: string\n}\n\nexport interface MicdropToolCall {\n name: string\n parameters: any\n output: any\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":"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","names":["PassThrough","MicdropErrorCode","PassThrough","MicdropClientCommands","MicdropServerCommands","PassThrough","EventEmitter","PassThrough","PassThrough"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent/Agent.ts","../src/agent/tools.ts","../src/agent/MockAgent.ts","../src/audio-convert.ts","../src/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/stt/STT.ts","../src/stt/FileSTT.ts","../src/stt/MockSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/waitForParams.ts"],"sourcesContent":["import { EventEmitter } from 'eventemitter3'\nimport { PassThrough, Readable, Writable } from 'stream'\nimport type { z } from 'zod'\nimport { Logger } from '../Logger'\nimport {\n MicdropAnswerMetadata,\n MicdropConversation,\n MicdropConversationItem,\n MicdropConversationMessage,\n MicdropConversationToolCall,\n MicdropConversationToolResult,\n MicdropToolCall,\n} from '../types'\nimport {\n AUTO_END_CALL_PROMPT,\n AUTO_END_CALL_TOOL_NAME,\n AUTO_IGNORE_USER_NOISE_PROMPT,\n AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n AUTO_SEMANTIC_TURN_PROMPT,\n AUTO_SEMANTIC_TURN_TOOL_NAME,\n Tool,\n} from './tools'\n\nexport interface AgentOptions {\n systemPrompt: string\n\n // Enable auto ending of the call when user asks to end the call\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoEndCall?: boolean | string\n\n // Enable detection of an incomplete sentence, and skip the answer (assistant waits)\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoSemanticTurn?: boolean | string\n\n // Ignore of the last user message when it's meaningless\n // You can provide a custom prompt to use instead of the default one by passing a string\n autoIgnoreUserNoise?: boolean | string\n\n // Extract a value from the answer\n // Value must be at the end of the answer, in JSON or between tags\n extract?: ExtractJsonOptions | ExtractTagOptions\n\n // Function called before any answer is generated\n // Return true to skip generation\n onBeforeAnswer?: (\n this: Agent,\n stream: Writable\n ) => void | boolean | Promise<boolean>\n}\n\nexport interface AgentEvents {\n Message: [MicdropConversationItem]\n CancelLastUserMessage: []\n SkipAnswer: []\n EndCall: []\n ToolCall: [MicdropToolCall]\n}\n\nexport interface ExtractOptions {\n callback?: (value: string) => void\n saveInMetadata?: boolean\n}\n\nexport interface ExtractJsonOptions extends ExtractOptions {\n json: true\n callback?: (value: any) => void\n}\n\nexport interface ExtractTagOptions extends ExtractOptions {\n startTag: string\n endTag: string\n}\n\nexport abstract class Agent<\n Options extends AgentOptions = AgentOptions,\n> extends EventEmitter<AgentEvents> {\n public logger?: Logger\n public conversation: MicdropConversation\n\n protected tools: Tool[]\n protected answerCount = 0\n protected answering = false\n\n constructor(protected options: Options) {\n super()\n this.conversation = [{ role: 'system', content: options.systemPrompt }]\n this.tools = this.getDefaultTools()\n }\n\n protected abstract generateAnswer(stream: PassThrough): Promise<void>\n abstract cancel(): void\n\n answer(): Readable {\n this.log('Start answering')\n const answerCount = ++this.answerCount\n const stream = new PassThrough()\n this.answering = true\n\n Promise.resolve()\n // Call hook onBeforeAnswer\n .then(() => this.options.onBeforeAnswer?.bind(this)(stream))\n // Generate answer (if not skipped)\n .then((skip) => {\n if (skip) return\n return this.generateAnswer(stream)\n })\n // End stream\n .finally(() => {\n if (stream.writable) {\n stream.end()\n }\n if (answerCount === this.answerCount) {\n this.answering = false\n }\n })\n\n return stream\n }\n\n addUserMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('user', text, metadata)\n }\n\n addAssistantMessage(text: string, metadata?: MicdropAnswerMetadata) {\n this.addMessage('assistant', text, metadata)\n }\n\n addTool<Schema extends z.ZodObject>(tool: Tool<Schema>) {\n this.tools.push(tool)\n }\n\n removeTool(name: string) {\n const index = this.tools.findIndex((tool) => tool.name === name)\n if (index !== -1) {\n this.tools.splice(index, 1)\n }\n }\n\n getTool(name: string): Tool | undefined {\n return this.tools.find((tool) => tool.name === name)\n }\n\n addMessage(\n role: 'user' | 'assistant' | 'system',\n text: string,\n metadata?: MicdropAnswerMetadata\n ) {\n this.log(`Adding ${role} message to conversation: ${text}`)\n const message: MicdropConversationMessage = {\n role,\n content: text,\n metadata,\n }\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n addToolMessage(\n message: MicdropConversationToolCall | MicdropConversationToolResult\n ) {\n this.log('Adding tool message:', message)\n this.conversation.push(message)\n this.emit('Message', message)\n }\n\n protected endCall() {\n this.log('Ending call')\n this.emit('EndCall')\n }\n\n protected cancelLastUserMessage() {\n this.log('Cancelling last user message')\n const lastMessageIndex = this.conversation.findLastIndex(\n (message) => message.role === 'user'\n )\n if (lastMessageIndex !== -1) {\n this.conversation.splice(lastMessageIndex, 1)\n }\n this.emit('CancelLastUserMessage')\n }\n\n protected skipAnswer() {\n this.log('Skipping answer')\n this.emit('SkipAnswer')\n }\n\n protected getDefaultTools() {\n const tools: Tool[] = []\n if (this.options.autoEndCall) {\n tools.push({\n name: AUTO_END_CALL_TOOL_NAME,\n description:\n typeof this.options.autoEndCall === 'string'\n ? this.options.autoEndCall\n : AUTO_END_CALL_PROMPT,\n execute: () => this.endCall(),\n })\n }\n if (this.options.autoSemanticTurn) {\n tools.push({\n name: AUTO_SEMANTIC_TURN_TOOL_NAME,\n description:\n typeof this.options.autoSemanticTurn === 'string'\n ? this.options.autoSemanticTurn\n : AUTO_SEMANTIC_TURN_PROMPT,\n skipAnswer: true,\n execute: () => this.skipAnswer(),\n })\n }\n if (this.options.autoIgnoreUserNoise) {\n tools.push({\n name: AUTO_IGNORE_USER_NOISE_TOOL_NAME,\n description:\n typeof this.options.autoIgnoreUserNoise === 'string'\n ? this.options.autoIgnoreUserNoise\n : AUTO_IGNORE_USER_NOISE_PROMPT,\n skipAnswer: true,\n execute: () => this.cancelLastUserMessage(),\n })\n }\n return tools\n }\n\n protected async executeTool(toolCall: MicdropConversationToolCall) {\n try {\n const tool = this.getTool(toolCall.toolName)\n if (!tool) {\n throw new Error(`Tool not found \"${toolCall.toolName}\"`)\n }\n\n this.log('Executing tool:', toolCall.toolName, toolCall.parameters)\n\n // Save tool call in conversation\n this.addToolMessage(toolCall)\n\n const parameters = JSON.parse(toolCall.parameters)\n const output = tool.execute ? await tool.execute(parameters) : {}\n\n // Save tool result in conversation\n this.addToolMessage({\n role: 'tool_result',\n toolCallId: toolCall.toolCallId,\n toolName: toolCall.toolName,\n output: JSON.stringify(output ?? null),\n })\n\n // Emit output\n if (tool.emitOutput) {\n this.emit('ToolCall', {\n name: toolCall.toolName,\n parameters,\n output,\n })\n }\n\n return {\n output,\n skipAnswer: tool.skipAnswer,\n }\n } catch (error: any) {\n console.error('[OpenaiAgent] Error executing tool:', error)\n return {\n output: {\n error: error.message,\n },\n }\n }\n }\n\n protected getExtractOptions(): ExtractTagOptions | undefined {\n const extract = this.options.extract\n if (!extract) return undefined\n if ('json' in extract && extract.json) {\n return { ...extract, startTag: '{', endTag: '}' }\n }\n if ('startTag' in extract && 'endTag' in extract) {\n return extract\n }\n return undefined\n }\n\n public extract(message: string) {\n const extractOptions = this.getExtractOptions()\n let metadata: MicdropAnswerMetadata | undefined = undefined\n\n // Extract value?\n if (extractOptions) {\n const startTagIndex = message.indexOf(extractOptions.startTag)\n if (startTagIndex !== -1) {\n // Find end tag\n let endTagIndex = message.lastIndexOf(extractOptions.endTag)\n if (endTagIndex === -1) endTagIndex = message.length + 1\n else endTagIndex += extractOptions.endTag.length\n const extractedText = message.slice(startTagIndex, endTagIndex).trim()\n\n // Parse extracted value\n try {\n const extractedValue =\n 'json' in extractOptions && extractOptions.json\n ? JSON.parse(extractedText)\n : extractedText\n\n // Call callback\n if (extractOptions.callback) {\n extractOptions.callback(extractedValue)\n }\n\n // Save in metadata\n if (extractOptions.saveInMetadata) {\n metadata = { extracted: extractedValue }\n }\n } catch (error) {\n console.error(\n `[OpenaiAgent] Error parsing extracted value (${extractedText}):`,\n error\n )\n }\n\n // Remove extracted value from message\n message = message.slice(0, startTagIndex).trimEnd()\n }\n }\n return { message, metadata }\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n this.cancel()\n }\n}\n","import type { z } from 'zod'\n\nexport interface Tool<Schema extends z.ZodObject = z.ZodObject> {\n name: string\n description: string\n inputSchema?: Schema\n execute?: (input: z.infer<Schema>) => any | Promise<any>\n skipAnswer?: boolean\n emitOutput?: boolean\n}\n\nexport const AUTO_END_CALL_TOOL_NAME = 'end_call'\nexport const AUTO_END_CALL_PROMPT =\n 'Call this tool only if user asks to end the call'\n\nexport const AUTO_SEMANTIC_TURN_TOOL_NAME = 'semantic_turn'\nexport const AUTO_SEMANTIC_TURN_PROMPT =\n 'Call this tool only if last user message is obviously an incomplete sentence that you need to wait for the end before answering'\n\nexport const AUTO_IGNORE_USER_NOISE_TOOL_NAME = 'ignore_user_noise'\nexport const AUTO_IGNORE_USER_NOISE_PROMPT =\n 'Call this tool only if last user message is just an interjection or a sound that expresses emotion, hesitation, or reaction (ex: \"Uh\", \"Ahem\", \"Hmm\", \"Ah\") but doesn\\'t carry any clear meaning like agreeing, refusing, or commanding'\n","import { PassThrough } from 'stream'\nimport { Agent } from './Agent'\n\nexport class MockAgent extends Agent {\n private i = 0\n\n constructor() {\n super({ systemPrompt: '' })\n }\n\n protected async generateAnswer(stream: PassThrough): Promise<void> {\n const message = `Assistant Message ${this.i++}`\n this.addAssistantMessage(message)\n stream.write(message)\n }\n\n cancel() {}\n}\n","import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'\nimport ffmpeg from 'fluent-ffmpeg'\nimport { PassThrough, Readable } from 'stream'\n\n// Setup ffmpeg\nffmpeg.setFfmpegPath(ffmpegInstaller.path)\n\n// Convert stream to WAV/PCM\nexport function convertToPCM(\n audioStream: Readable,\n sampleRate = 16000,\n bitDepth = 16\n) {\n const pcmStream = new PassThrough()\n ffmpeg(audioStream)\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec(`pcm_s${bitDepth}le`)\n .format(`s${bitDepth}le`)\n .on('error', (error) => {\n console.error('Error converting audio stream:', error.message)\n })\n .pipe(pcmStream)\n return pcmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate).pipe(webmStream)\n return webmStream\n}\n\n// Convert PCM stream to WebM/Opus\nexport function convertPCMToOpus(audioStream: Readable, sampleRate = 16000) {\n const webmStream = new PassThrough()\n ffmpegToOpus(ffmpeg(audioStream), sampleRate)\n .inputFormat('s16le')\n .inputOptions(['-f s16le', '-ar 16000', '-ac 1'])\n .pipe(webmStream)\n return webmStream\n}\n\nfunction ffmpegToOpus(ffmpegCommand: ffmpeg.FfmpegCommand, sampleRate = 16000) {\n return ffmpegCommand\n .audioChannels(1)\n .audioFrequency(sampleRate)\n .audioCodec('libopus')\n .format('webm')\n .outputOptions([\n '-application audio',\n `-ac 1`,\n `-ar ${sampleRate}`,\n `-b:a 64k`,\n `-f webm`,\n `-map_metadata -1`,\n ])\n .on('error', (error) => {\n console.error('Error converting to Opus: ', error.message)\n })\n}\n","import WebSocket from 'ws'\n\nexport enum MicdropErrorCode {\n BadRequest = 4400,\n Unauthorized = 4401,\n NotFound = 4404,\n}\n\nexport class MicdropError extends Error {\n code: number\n\n constructor(code: number, message: string) {\n super(message)\n this.code = code\n }\n}\n\nexport function handleError(socket: WebSocket, error: unknown) {\n if (error instanceof MicdropError) {\n socket.close(error.code, error.message)\n } else {\n console.error(error)\n socket.close(1011)\n }\n socket.terminate()\n}\n","export class Logger {\n constructor(private readonly name: string) {}\n\n log(...message: any[]) {\n const time = process.uptime().toFixed(3)\n console.log(`[${this.name} ${time}]`, ...message)\n }\n}\n","import { Duplex, PassThrough, Readable } from 'stream'\nimport { WebSocket } from 'ws'\nimport type { Agent } from './agent'\nimport { Logger } from './Logger'\nimport type { STT } from './stt'\nimport type { TTS } from './tts'\nimport {\n MicdropCallSummary,\n MicdropClientCommands,\n MicdropConversationItem,\n MicdropServerCommands,\n} from './types'\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n onEnd?(call: MicdropCallSummary): void\n}\n\nexport class MicdropServer {\n public socket: WebSocket | null = null\n public config: MicdropConfig | null = null\n public logger?: Logger\n\n private startTime = Date.now()\n private lastMessageSpeeched?: MicdropConversationItem\n\n // Queue system for operations\n private operationQueue: Array<() => Promise<void>> = []\n private isProcessingQueue = false\n\n // When user is speaking, we're streaming chunks for STT\n private currentUserStream?: Duplex\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscript)\n\n // Setup agent\n this.config.agent.on('Message', (message) =>\n this.socket?.send(\n `${MicdropServerCommands.Message} ${JSON.stringify(message)}`\n )\n )\n this.config.agent.on('CancelLastUserMessage', () =>\n this.socket?.send(MicdropServerCommands.CancelLastUserMessage)\n )\n this.config.agent.on('SkipAnswer', () =>\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n )\n this.config.agent.on('EndCall', () =>\n this.socket?.send(MicdropServerCommands.EndCall)\n )\n this.config.agent.on('ToolCall', (toolCall) =>\n this.socket?.send(\n `${MicdropServerCommands.ToolCall} ${JSON.stringify(toolCall)}`\n )\n )\n\n // Assistant speaks first\n this.sendFirstMessage()\n\n // Listen to events\n socket.on('close', this.onClose)\n socket.on('message', this.onMessage)\n }\n\n private log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n private async processQueue() {\n if (this.isProcessingQueue || this.operationQueue.length === 0) return\n\n this.isProcessingQueue = true\n\n while (this.operationQueue.length > 0) {\n const operation = this.operationQueue.shift()\n if (operation) {\n try {\n await operation()\n } catch (error) {\n this.log('Error processing queued operation:', error)\n }\n }\n }\n\n this.isProcessingQueue = false\n }\n\n private queueOperation(operation: () => Promise<void>) {\n this.operationQueue.push(operation)\n this.processQueue()\n }\n\n public cancel() {\n this.config?.tts.cancel()\n this.config?.agent.cancel()\n // Clear the queue\n this.operationQueue = []\n }\n\n private onClose = () => {\n if (!this.config) return\n this.log('Connection closed')\n const duration = Math.round((Date.now() - this.startTime) / 1000)\n\n // Destroy instances\n this.config.agent.destroy()\n this.config.stt.destroy()\n this.config.tts.destroy()\n\n // End call callback\n this.config.onEnd?.({\n conversation: this.config.agent.conversation.slice(1), // Remove system message\n duration,\n })\n\n // Unset params\n this.socket = null\n this.config = null\n }\n\n private onMessage = async (message: Buffer) => {\n if (message.byteLength === 0) return\n if (!Buffer.isBuffer(message)) {\n this.log('Message is not a buffer')\n return\n }\n\n // Commands\n if (message.byteLength < 15) {\n const cmd = message.toString()\n this.log(`Command: ${cmd}`)\n\n if (cmd === MicdropClientCommands.StartSpeaking) {\n // User started speaking\n this.onStartSpeaking()\n } else if (cmd === MicdropClientCommands.Mute) {\n // User muted the call\n this.onMute()\n } else if (cmd === MicdropClientCommands.StopSpeaking) {\n // User stopped speaking\n this.onStopSpeaking()\n }\n }\n\n // Audio chunk\n else if (this.currentUserStream) {\n this.log(`Received chunk (${message.byteLength} bytes)`)\n this.currentUserStream.write(message)\n }\n }\n\n private onMute() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.currentUserStream?.end()\n this.currentUserStream = new PassThrough()\n this.config.stt.transcribe(this.currentUserStream)\n this.cancel()\n }\n\n private onStopSpeaking() {\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n\n const conversation = this.config?.agent.conversation\n const lastMessage = conversation?.[conversation.length - 1]\n if (\n lastMessage?.role === 'user' &&\n this.lastMessageSpeeched !== lastMessage\n ) {\n this.log(\n 'User stopped speaking and a transcript already exists, answering'\n )\n this.cancel()\n this.answer()\n }\n }\n\n private onTranscript = async (transcript: string) => {\n if (!this.config) return\n this.log(`User transcript: \"${transcript}\"`)\n this.config.agent.addUserMessage(transcript)\n\n // Answer if user stopped speaking\n if (!this.currentUserStream) {\n this.log('User stopped speaking, answering')\n this.cancel()\n this.answer()\n }\n }\n\n private sendFirstMessage() {\n if (!this.config) return\n if (this.config.firstMessage) {\n // Send first message\n this.config.agent.addAssistantMessage(this.config.firstMessage)\n this.speak(this.config.firstMessage)\n } else if (this.config.generateFirstMessage) {\n // Generate first message\n this.answer()\n } else {\n // Skip answer if no first message is provided\n // to avoid keeping the client in a processing state\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n }\n }\n\n public answer() {\n this.queueOperation(async () => {\n await this._answer()\n })\n }\n\n private async _answer() {\n if (!this.config) return\n\n // Prevent answering twice\n const lastMessage =\n this.config.agent.conversation[this.config.agent.conversation.length - 1]\n if (this.lastMessageSpeeched === lastMessage) {\n this.log('Already answered, skipping')\n return\n }\n this.lastMessageSpeeched = lastMessage\n\n try {\n // LLM: Generate answer\n const stream = this.config.agent.answer()\n\n // TTS: Generate answer audio\n await this._speak(stream)\n } catch (error) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n throw error\n }\n }\n\n // Run text-to-speech and send to client\n public speak(message: string | Readable) {\n this.queueOperation(async () => {\n await this._speak(message)\n })\n }\n\n private async _speak(message: string | Readable) {\n if (!this.socket || !this.config) return\n\n // Convert message to stream if needed\n let textStream: Readable\n if (typeof message === 'string') {\n const stream = new PassThrough()\n stream.write(message)\n stream.end()\n textStream = stream\n } else {\n textStream = message\n }\n\n // Run TTS\n const audio = this.config.tts.speak(textStream)\n\n // Send audio to client\n await this._sendAudio(audio)\n }\n\n public sendAudio(audio: Readable) {\n this.queueOperation(async () => {\n await this._sendAudio(audio)\n })\n }\n\n private async _sendAudio(audio: Readable) {\n if (!this.socket) return\n if (!audio.readable) {\n this.log('Non readable audio, skipping', audio)\n return\n }\n\n // Wait for audio stream to complete\n await new Promise<void>((resolve, reject) => {\n audio.on('data', (chunk) => {\n this.log(`Send audio chunk (${chunk.byteLength} bytes)`)\n this.socket?.send(chunk)\n })\n audio.on('error', (error) => {\n this.log('Error in audio stream', error)\n reject(error)\n })\n audio.on('end', () => {\n this.log('Audio stream ended')\n resolve()\n })\n })\n }\n}\n","export enum MicdropClientCommands {\n StartSpeaking = 'StartSpeaking',\n StopSpeaking = 'StopSpeaking',\n Mute = 'Mute',\n}\n\nexport enum MicdropServerCommands {\n Message = 'Message',\n CancelLastUserMessage = 'CancelLastUserMessage',\n SkipAnswer = 'SkipAnswer',\n EndCall = 'EndCall',\n ToolCall = 'ToolCall',\n}\n\nexport interface MicdropCallSummary {\n conversation: MicdropConversation\n duration: number\n}\n\nexport type MicdropConversationItem =\n | MicdropConversationMessage\n | MicdropConversationToolCall\n | MicdropConversationToolResult\n\nexport type MicdropConversation = Array<MicdropConversationItem>\n\nexport type MicdropAnswerMetadata = {\n [key: string]: any\n}\n\nexport interface MicdropConversationMessage<\n Data extends MicdropAnswerMetadata = MicdropAnswerMetadata,\n> {\n role: 'system' | 'user' | 'assistant'\n content: string\n metadata?: Data\n}\n\nexport interface MicdropConversationToolCall {\n role: 'tool_call'\n toolCallId: string\n toolName: string\n parameters: string\n}\n\nexport interface MicdropConversationToolResult {\n role: 'tool_result'\n toolCallId: string\n toolName: string\n output: string\n}\n\nexport interface MicdropToolCall {\n name: string\n parameters: any\n output: any\n}\n\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\n// Audio mime type to extension map\nconst MIME_TYPE_TO_EXTENSION = {\n 'audio/wav': 'wav',\n 'audio/ogg': 'ogg',\n 'audio/mpeg': 'mp3',\n 'audio/webm': 'webm',\n 'audio/mp4': 'mp4',\n 'audio/flac': 'flac',\n} as const\n\nexport interface STTEvents {\n Transcript: [string]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n protected mimeType?: keyof typeof MIME_TYPE_TO_EXTENSION\n public logger?: Logger\n\n // Set stream of audio to transcribe\n transcribe(audioStream: Readable) {\n // Detect mime type at first chunk\n audioStream.once('data', (chunk) => {\n this.mimeType = this.detectMimeType(chunk)\n })\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.removeAllListeners()\n }\n\n protected get extension(): string {\n return (this.mimeType && MIME_TYPE_TO_EXTENSION[this.mimeType]) || 'bin'\n }\n\n private detectMimeType(\n chunk: ArrayBuffer\n ): keyof typeof MIME_TYPE_TO_EXTENSION {\n if (!chunk || chunk.byteLength === 0) {\n throw new Error('Unable to detect mime type (empty chunk)')\n }\n\n const arr = new Uint8Array(chunk)\n\n // WEBM: 1A 45 DF A3\n if (\n arr[0] === 0x1a &&\n arr[1] === 0x45 &&\n arr[2] === 0xdf &&\n arr[3] === 0xa3\n ) {\n return 'audio/webm'\n }\n // OGG: 4F 67 67 53\n if (\n arr[0] === 0x4f &&\n arr[1] === 0x67 &&\n arr[2] === 0x67 &&\n arr[3] === 0x53\n ) {\n return 'audio/ogg'\n }\n // WAV: 52 49 46 46 ... 57 41 56 45\n if (\n arr[0] === 0x52 &&\n arr[1] === 0x49 &&\n arr[2] === 0x46 &&\n arr[3] === 0x46 &&\n arr[8] === 0x57 &&\n arr[9] === 0x41 &&\n arr[10] === 0x56 &&\n arr[11] === 0x45\n ) {\n return 'audio/wav'\n }\n // MP3: 49 44 33\n if (arr[0] === 0x49 && arr[1] === 0x44 && arr[2] === 0x33) {\n return 'audio/mpeg'\n }\n // MP4/M4A: 00 00 00 .. 66 74 79 70\n if (\n arr[4] === 0x66 &&\n arr[5] === 0x74 &&\n arr[6] === 0x79 &&\n arr[7] === 0x70\n ) {\n return 'audio/mp4'\n }\n // FLAC: 66 4c 61 43\n if (\n arr[0] === 0x66 &&\n arr[1] === 0x4c &&\n arr[2] === 0x61 &&\n arr[3] === 0x43\n ) {\n return 'audio/flac'\n }\n this.log('Unable to detect mime type, using default', chunk)\n return 'audio/wav'\n }\n}\n","import { Readable } from 'stream'\nimport { STT } from './STT'\n\n/**\n * Abstract class for STT, converting stream to file before transcribing\n */\n\nexport abstract class FileSTT extends STT {\n abstract transcribeFile(file: File): Promise<string>\n\n transcribe(audioStream: Readable) {\n super.transcribe(audioStream)\n\n // Convert stream to file\n this.log('Converting stream to file...')\n\n const chunks: Buffer[] = []\n audioStream.on('data', (chunk) => {\n chunks.push(chunk)\n })\n\n audioStream.on('end', async () => {\n if (chunks.length === 0) return\n const arrayBuffer = Buffer.concat(chunks)\n const file = new File([arrayBuffer], `audio.${this.extension}`, {\n type: this.mimeType,\n })\n\n // Transcribe file with implementation\n this.log('Transcribing file...')\n const transcript = await this.transcribeFile(file)\n this.emit('Transcript', transcript)\n })\n }\n}\n","import { FileSTT } from './FileSTT'\n\nexport class MockSTT extends FileSTT {\n private i = 0\n\n async transcribeFile(file: File) {\n return `User Message ${this.i++}`\n }\n}\n","import * as fs from 'fs'\nimport { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\n\nexport class MockTTS extends TTS {\n constructor(private audioFilePaths: string[]) {\n super()\n }\n\n speak(textStream: Readable) {\n const audioStream = new PassThrough()\n textStream.once('data', async () => {\n for (const filePath of this.audioFilePaths) {\n await new Promise((resolve) => setTimeout(resolve, 200))\n const audioBuffer = fs.readFileSync(filePath)\n this.log(`Loaded chunk (${audioBuffer.length} bytes)`)\n audioStream.write(audioBuffer)\n }\n audioStream.end()\n })\n return audioStream\n }\n\n cancel() {}\n}\n","import { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport abstract class TTS {\n public logger?: Logger\n\n abstract speak(textStream: Readable): Readable\n abstract cancel(): void\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n\n destroy() {\n this.log('Destroyed')\n this.cancel()\n }\n}\n","import { WebSocket } from 'ws'\nimport { MicdropError, MicdropErrorCode } from './errors'\n\nexport async function waitForParams<CallParams>(\n socket: WebSocket,\n validate: (params: any) => CallParams\n): Promise<CallParams> {\n return new Promise<CallParams>((resolve, reject) => {\n // Handle timeout\n const timeout = setTimeout(() => {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Missing params'))\n }, 3000)\n\n const onParams = (payload: string) => {\n // Clear timeout and listener\n clearTimeout(timeout)\n socket.off('message', onParams)\n\n try {\n // Parse JSON payload\n const params = validate(JSON.parse(payload))\n resolve(params)\n } catch (error) {\n reject(new MicdropError(MicdropErrorCode.BadRequest, 'Invalid params'))\n }\n }\n\n // Listen for params\n socket.on('message', onParams)\n })\n}\n"],"mappings":"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","names":["PassThrough","MicdropErrorCode","PassThrough","MicdropClientCommands","MicdropServerCommands","PassThrough","EventEmitter","PassThrough","PassThrough"]}
|