@micdrop/server 2.2.3 → 2.2.4
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.d.mts +28 -3
- package/dist/index.d.ts +28 -3
- package/dist/index.js +125 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +124 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -60,7 +60,7 @@ interface Tool<Schema extends z.ZodObject = z.ZodObject> {
|
|
|
60
60
|
name: string;
|
|
61
61
|
description: string;
|
|
62
62
|
inputSchema?: Schema;
|
|
63
|
-
execute?: (input: z.infer<Schema
|
|
63
|
+
execute?: (input: z.infer<Schema>, agent: Agent) => any | Promise<any>;
|
|
64
64
|
skipAnswer?: boolean;
|
|
65
65
|
emitOutput?: boolean;
|
|
66
66
|
}
|
|
@@ -85,6 +85,7 @@ interface AgentEvents {
|
|
|
85
85
|
SkipAnswer: [];
|
|
86
86
|
EndCall: [];
|
|
87
87
|
ToolCall: [MicdropToolCall];
|
|
88
|
+
Failed: [];
|
|
88
89
|
}
|
|
89
90
|
interface ExtractOptions {
|
|
90
91
|
callback?: (value: string) => void;
|
|
@@ -102,7 +103,7 @@ declare abstract class Agent<Options extends AgentOptions = AgentOptions> extend
|
|
|
102
103
|
protected options: Options;
|
|
103
104
|
logger?: Logger;
|
|
104
105
|
conversation: MicdropConversation;
|
|
105
|
-
|
|
106
|
+
tools: Tool[];
|
|
106
107
|
protected answerCount: number;
|
|
107
108
|
protected answering: boolean;
|
|
108
109
|
constructor(options: Options);
|
|
@@ -138,6 +139,30 @@ declare abstract class Agent<Options extends AgentOptions = AgentOptions> extend
|
|
|
138
139
|
destroy(): void;
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
interface FallbackAgentOptions {
|
|
143
|
+
factories: Array<() => Agent>;
|
|
144
|
+
}
|
|
145
|
+
declare class FallbackAgent extends Agent {
|
|
146
|
+
private readonly fallbackOptions;
|
|
147
|
+
private agent;
|
|
148
|
+
private agentIndex;
|
|
149
|
+
constructor(fallbackOptions: FallbackAgentOptions);
|
|
150
|
+
extract(message: string): {
|
|
151
|
+
message: string;
|
|
152
|
+
metadata: MicdropAnswerMetadata | undefined;
|
|
153
|
+
};
|
|
154
|
+
protected generateAnswer(stream: PassThrough): Promise<void>;
|
|
155
|
+
cancel(): void;
|
|
156
|
+
destroy(): void;
|
|
157
|
+
private pipeAnswer;
|
|
158
|
+
private startNextAgent;
|
|
159
|
+
private onMessage;
|
|
160
|
+
private onCancelLastUserMessage;
|
|
161
|
+
private onSkipAnswer;
|
|
162
|
+
private onEndCall;
|
|
163
|
+
private onToolCall;
|
|
164
|
+
}
|
|
165
|
+
|
|
141
166
|
declare class MockAgent extends Agent {
|
|
142
167
|
private i;
|
|
143
168
|
constructor();
|
|
@@ -297,4 +322,4 @@ declare class MicdropRecorder extends EventEmitter<MicdropRecorderEvents> {
|
|
|
297
322
|
|
|
298
323
|
declare function waitForParams<CallParams>(socket: WebSocket$1, validate: (params: any) => CallParams): Promise<CallParams>;
|
|
299
324
|
|
|
300
|
-
export { AUTO_END_CALL_PROMPT, AUTO_END_CALL_TOOL_NAME, AUTO_IGNORE_USER_NOISE_PROMPT, AUTO_IGNORE_USER_NOISE_TOOL_NAME, AUTO_SEMANTIC_TURN_PROMPT, AUTO_SEMANTIC_TURN_TOOL_NAME, Agent, type AgentEvents, type AgentOptions, type AudioMessage, type DeepPartial, type ExtractJsonOptions, type ExtractOptions, type ExtractTagOptions, FallbackSTT, type FallbackSTTOptions, FallbackTTS, type FallbackTTSOptions, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationItem, type MicdropConversationMessage, type MicdropConversationToolCall, type MicdropConversationToolResult, MicdropError, MicdropErrorCode, MicdropRecorder, type MicdropRecorderEvents, MicdropServer, MicdropServerCommands, type MicdropServerEvents, type MicdropToolCall, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, type TTSEvents, type Tool, handleError, waitForParams };
|
|
325
|
+
export { AUTO_END_CALL_PROMPT, AUTO_END_CALL_TOOL_NAME, AUTO_IGNORE_USER_NOISE_PROMPT, AUTO_IGNORE_USER_NOISE_TOOL_NAME, AUTO_SEMANTIC_TURN_PROMPT, AUTO_SEMANTIC_TURN_TOOL_NAME, Agent, type AgentEvents, type AgentOptions, type AudioMessage, type DeepPartial, type ExtractJsonOptions, type ExtractOptions, type ExtractTagOptions, FallbackAgent, type FallbackAgentOptions, FallbackSTT, type FallbackSTTOptions, FallbackTTS, type FallbackTTSOptions, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationItem, type MicdropConversationMessage, type MicdropConversationToolCall, type MicdropConversationToolResult, MicdropError, MicdropErrorCode, MicdropRecorder, type MicdropRecorderEvents, MicdropServer, MicdropServerCommands, type MicdropServerEvents, type MicdropToolCall, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, type TTSEvents, type Tool, handleError, waitForParams };
|
package/dist/index.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ interface Tool<Schema extends z.ZodObject = z.ZodObject> {
|
|
|
60
60
|
name: string;
|
|
61
61
|
description: string;
|
|
62
62
|
inputSchema?: Schema;
|
|
63
|
-
execute?: (input: z.infer<Schema
|
|
63
|
+
execute?: (input: z.infer<Schema>, agent: Agent) => any | Promise<any>;
|
|
64
64
|
skipAnswer?: boolean;
|
|
65
65
|
emitOutput?: boolean;
|
|
66
66
|
}
|
|
@@ -85,6 +85,7 @@ interface AgentEvents {
|
|
|
85
85
|
SkipAnswer: [];
|
|
86
86
|
EndCall: [];
|
|
87
87
|
ToolCall: [MicdropToolCall];
|
|
88
|
+
Failed: [];
|
|
88
89
|
}
|
|
89
90
|
interface ExtractOptions {
|
|
90
91
|
callback?: (value: string) => void;
|
|
@@ -102,7 +103,7 @@ declare abstract class Agent<Options extends AgentOptions = AgentOptions> extend
|
|
|
102
103
|
protected options: Options;
|
|
103
104
|
logger?: Logger;
|
|
104
105
|
conversation: MicdropConversation;
|
|
105
|
-
|
|
106
|
+
tools: Tool[];
|
|
106
107
|
protected answerCount: number;
|
|
107
108
|
protected answering: boolean;
|
|
108
109
|
constructor(options: Options);
|
|
@@ -138,6 +139,30 @@ declare abstract class Agent<Options extends AgentOptions = AgentOptions> extend
|
|
|
138
139
|
destroy(): void;
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
interface FallbackAgentOptions {
|
|
143
|
+
factories: Array<() => Agent>;
|
|
144
|
+
}
|
|
145
|
+
declare class FallbackAgent extends Agent {
|
|
146
|
+
private readonly fallbackOptions;
|
|
147
|
+
private agent;
|
|
148
|
+
private agentIndex;
|
|
149
|
+
constructor(fallbackOptions: FallbackAgentOptions);
|
|
150
|
+
extract(message: string): {
|
|
151
|
+
message: string;
|
|
152
|
+
metadata: MicdropAnswerMetadata | undefined;
|
|
153
|
+
};
|
|
154
|
+
protected generateAnswer(stream: PassThrough): Promise<void>;
|
|
155
|
+
cancel(): void;
|
|
156
|
+
destroy(): void;
|
|
157
|
+
private pipeAnswer;
|
|
158
|
+
private startNextAgent;
|
|
159
|
+
private onMessage;
|
|
160
|
+
private onCancelLastUserMessage;
|
|
161
|
+
private onSkipAnswer;
|
|
162
|
+
private onEndCall;
|
|
163
|
+
private onToolCall;
|
|
164
|
+
}
|
|
165
|
+
|
|
141
166
|
declare class MockAgent extends Agent {
|
|
142
167
|
private i;
|
|
143
168
|
constructor();
|
|
@@ -297,4 +322,4 @@ declare class MicdropRecorder extends EventEmitter<MicdropRecorderEvents> {
|
|
|
297
322
|
|
|
298
323
|
declare function waitForParams<CallParams>(socket: WebSocket$1, validate: (params: any) => CallParams): Promise<CallParams>;
|
|
299
324
|
|
|
300
|
-
export { AUTO_END_CALL_PROMPT, AUTO_END_CALL_TOOL_NAME, AUTO_IGNORE_USER_NOISE_PROMPT, AUTO_IGNORE_USER_NOISE_TOOL_NAME, AUTO_SEMANTIC_TURN_PROMPT, AUTO_SEMANTIC_TURN_TOOL_NAME, Agent, type AgentEvents, type AgentOptions, type AudioMessage, type DeepPartial, type ExtractJsonOptions, type ExtractOptions, type ExtractTagOptions, FallbackSTT, type FallbackSTTOptions, FallbackTTS, type FallbackTTSOptions, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationItem, type MicdropConversationMessage, type MicdropConversationToolCall, type MicdropConversationToolResult, MicdropError, MicdropErrorCode, MicdropRecorder, type MicdropRecorderEvents, MicdropServer, MicdropServerCommands, type MicdropServerEvents, type MicdropToolCall, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, type TTSEvents, type Tool, handleError, waitForParams };
|
|
325
|
+
export { AUTO_END_CALL_PROMPT, AUTO_END_CALL_TOOL_NAME, AUTO_IGNORE_USER_NOISE_PROMPT, AUTO_IGNORE_USER_NOISE_TOOL_NAME, AUTO_SEMANTIC_TURN_PROMPT, AUTO_SEMANTIC_TURN_TOOL_NAME, Agent, type AgentEvents, type AgentOptions, type AudioMessage, type DeepPartial, type ExtractJsonOptions, type ExtractOptions, type ExtractTagOptions, FallbackAgent, type FallbackAgentOptions, FallbackSTT, type FallbackSTTOptions, FallbackTTS, type FallbackTTSOptions, Logger, type MicdropAnswerMetadata, type MicdropCallSummary, MicdropClientCommands, type MicdropConfig, type MicdropConversation, type MicdropConversationItem, type MicdropConversationMessage, type MicdropConversationToolCall, type MicdropConversationToolResult, MicdropError, MicdropErrorCode, MicdropRecorder, type MicdropRecorderEvents, MicdropServer, MicdropServerCommands, type MicdropServerEvents, type MicdropToolCall, MockAgent, MockSTT, MockTTS, STT, type STTEvents, TTS, type TTSEvents, type Tool, handleError, waitForParams };
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ __export(index_exports, {
|
|
|
37
37
|
AUTO_SEMANTIC_TURN_PROMPT: () => AUTO_SEMANTIC_TURN_PROMPT,
|
|
38
38
|
AUTO_SEMANTIC_TURN_TOOL_NAME: () => AUTO_SEMANTIC_TURN_TOOL_NAME,
|
|
39
39
|
Agent: () => Agent,
|
|
40
|
+
FallbackAgent: () => FallbackAgent,
|
|
40
41
|
FallbackSTT: () => FallbackSTT,
|
|
41
42
|
FallbackTTS: () => FallbackTTS,
|
|
42
43
|
Logger: () => Logger,
|
|
@@ -153,7 +154,7 @@ var Agent = class extends import_eventemitter3.EventEmitter {
|
|
|
153
154
|
tools.push({
|
|
154
155
|
name: AUTO_END_CALL_TOOL_NAME,
|
|
155
156
|
description: typeof this.options.autoEndCall === "string" ? this.options.autoEndCall : AUTO_END_CALL_PROMPT,
|
|
156
|
-
execute: () =>
|
|
157
|
+
execute: (_input, agent) => agent.endCall()
|
|
157
158
|
});
|
|
158
159
|
}
|
|
159
160
|
if (this.options.autoSemanticTurn) {
|
|
@@ -161,7 +162,7 @@ var Agent = class extends import_eventemitter3.EventEmitter {
|
|
|
161
162
|
name: AUTO_SEMANTIC_TURN_TOOL_NAME,
|
|
162
163
|
description: typeof this.options.autoSemanticTurn === "string" ? this.options.autoSemanticTurn : AUTO_SEMANTIC_TURN_PROMPT,
|
|
163
164
|
skipAnswer: true,
|
|
164
|
-
execute: () =>
|
|
165
|
+
execute: (_input, agent) => agent.skipAnswer()
|
|
165
166
|
});
|
|
166
167
|
}
|
|
167
168
|
if (this.options.autoIgnoreUserNoise) {
|
|
@@ -169,7 +170,7 @@ var Agent = class extends import_eventemitter3.EventEmitter {
|
|
|
169
170
|
name: AUTO_IGNORE_USER_NOISE_TOOL_NAME,
|
|
170
171
|
description: typeof this.options.autoIgnoreUserNoise === "string" ? this.options.autoIgnoreUserNoise : AUTO_IGNORE_USER_NOISE_PROMPT,
|
|
171
172
|
skipAnswer: true,
|
|
172
|
-
execute: () =>
|
|
173
|
+
execute: (_input, agent) => agent.cancelLastUserMessage()
|
|
173
174
|
});
|
|
174
175
|
}
|
|
175
176
|
return tools;
|
|
@@ -183,7 +184,7 @@ var Agent = class extends import_eventemitter3.EventEmitter {
|
|
|
183
184
|
this.log("Executing tool:", toolCall.toolName, toolCall.parameters);
|
|
184
185
|
this.addToolMessage(toolCall);
|
|
185
186
|
const parameters = JSON.parse(toolCall.parameters);
|
|
186
|
-
const output = tool.execute ? await tool.execute(parameters) : {};
|
|
187
|
+
const output = tool.execute ? await tool.execute(parameters, this) : {};
|
|
187
188
|
this.addToolMessage({
|
|
188
189
|
role: "tool_result",
|
|
189
190
|
toolCallId: toolCall.toolCallId,
|
|
@@ -260,6 +261,125 @@ var Agent = class extends import_eventemitter3.EventEmitter {
|
|
|
260
261
|
}
|
|
261
262
|
};
|
|
262
263
|
|
|
264
|
+
// src/Logger.ts
|
|
265
|
+
var Logger = class {
|
|
266
|
+
constructor(name) {
|
|
267
|
+
this.name = name;
|
|
268
|
+
}
|
|
269
|
+
log(...message) {
|
|
270
|
+
const time = process.uptime().toFixed(3);
|
|
271
|
+
console.log(`[${this.name} ${time}]`, ...message);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// src/agent/FallbackAgent.ts
|
|
276
|
+
var FallbackAgent = class extends Agent {
|
|
277
|
+
// Start at -1 because we need to increment it before using it
|
|
278
|
+
constructor(fallbackOptions) {
|
|
279
|
+
super({ systemPrompt: "" });
|
|
280
|
+
this.fallbackOptions = fallbackOptions;
|
|
281
|
+
this.agent = null;
|
|
282
|
+
this.agentIndex = -1;
|
|
283
|
+
this.onMessage = (message) => {
|
|
284
|
+
this.emit("Message", message);
|
|
285
|
+
};
|
|
286
|
+
this.onCancelLastUserMessage = () => {
|
|
287
|
+
this.emit("CancelLastUserMessage");
|
|
288
|
+
};
|
|
289
|
+
this.onSkipAnswer = () => {
|
|
290
|
+
this.emit("SkipAnswer");
|
|
291
|
+
};
|
|
292
|
+
this.onEndCall = () => {
|
|
293
|
+
this.emit("EndCall");
|
|
294
|
+
};
|
|
295
|
+
this.onToolCall = (toolCall) => {
|
|
296
|
+
this.emit("ToolCall", toolCall);
|
|
297
|
+
};
|
|
298
|
+
if (this.fallbackOptions.factories.length === 0) {
|
|
299
|
+
throw new Error("FallbackAgent: No factories provided");
|
|
300
|
+
}
|
|
301
|
+
this.startNextAgent();
|
|
302
|
+
}
|
|
303
|
+
// Delegate extraction to the active agent (extract config lives on children)
|
|
304
|
+
extract(message) {
|
|
305
|
+
return this.agent ? this.agent.extract(message) : super.extract(message);
|
|
306
|
+
}
|
|
307
|
+
async generateAnswer(stream) {
|
|
308
|
+
for (let attempt = 0; attempt < this.fallbackOptions.factories.length; attempt++) {
|
|
309
|
+
const agent = this.agent;
|
|
310
|
+
if (!agent) return;
|
|
311
|
+
let failed = false;
|
|
312
|
+
const onFailed = () => {
|
|
313
|
+
failed = true;
|
|
314
|
+
};
|
|
315
|
+
agent.once("Failed", onFailed);
|
|
316
|
+
try {
|
|
317
|
+
await this.pipeAnswer(agent, stream);
|
|
318
|
+
} finally {
|
|
319
|
+
agent.off("Failed", onFailed);
|
|
320
|
+
}
|
|
321
|
+
if (!failed) return;
|
|
322
|
+
this.log("Agent failed, trying next agent");
|
|
323
|
+
this.startNextAgent();
|
|
324
|
+
}
|
|
325
|
+
this.log("All agents failed");
|
|
326
|
+
this.emit("Failed");
|
|
327
|
+
}
|
|
328
|
+
cancel() {
|
|
329
|
+
this.agent?.cancel();
|
|
330
|
+
}
|
|
331
|
+
destroy() {
|
|
332
|
+
super.destroy();
|
|
333
|
+
this.agent?.destroy();
|
|
334
|
+
this.agent = null;
|
|
335
|
+
this.agentIndex = -1;
|
|
336
|
+
}
|
|
337
|
+
// Run the child agent and forward its answer chunks to our own stream
|
|
338
|
+
pipeAnswer(agent, stream) {
|
|
339
|
+
return new Promise((resolve) => {
|
|
340
|
+
const answerStream = agent.answer();
|
|
341
|
+
answerStream.on("data", (chunk) => {
|
|
342
|
+
if (stream.writable) {
|
|
343
|
+
stream.write(chunk);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
answerStream.on("end", resolve);
|
|
347
|
+
answerStream.on("error", resolve);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
startNextAgent() {
|
|
351
|
+
this.agentIndex++;
|
|
352
|
+
if (this.agentIndex >= this.fallbackOptions.factories.length) {
|
|
353
|
+
this.agentIndex = 0;
|
|
354
|
+
}
|
|
355
|
+
const previousAgent = this.agent;
|
|
356
|
+
const isFirstAgent = previousAgent === null;
|
|
357
|
+
const agent = this.fallbackOptions.factories[this.agentIndex]();
|
|
358
|
+
this.agent = agent;
|
|
359
|
+
if (isFirstAgent) {
|
|
360
|
+
this.conversation = agent.conversation;
|
|
361
|
+
this.tools = agent.tools;
|
|
362
|
+
} else {
|
|
363
|
+
if (agent.conversation[0]?.role === "system") {
|
|
364
|
+
this.conversation[0] = agent.conversation[0];
|
|
365
|
+
}
|
|
366
|
+
agent.conversation = this.conversation;
|
|
367
|
+
agent.tools = this.tools;
|
|
368
|
+
}
|
|
369
|
+
agent.on("Message", this.onMessage);
|
|
370
|
+
agent.on("CancelLastUserMessage", this.onCancelLastUserMessage);
|
|
371
|
+
agent.on("SkipAnswer", this.onSkipAnswer);
|
|
372
|
+
agent.on("EndCall", this.onEndCall);
|
|
373
|
+
agent.on("ToolCall", this.onToolCall);
|
|
374
|
+
previousAgent?.destroy();
|
|
375
|
+
setTimeout(() => {
|
|
376
|
+
if (this.agent && this.logger) {
|
|
377
|
+
this.agent.logger = new Logger(this.agent.constructor.name);
|
|
378
|
+
}
|
|
379
|
+
}, 0);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
|
|
263
383
|
// src/agent/MockAgent.ts
|
|
264
384
|
var MockAgent = class extends Agent {
|
|
265
385
|
constructor() {
|
|
@@ -298,17 +418,6 @@ function handleError(socket, error) {
|
|
|
298
418
|
socket.terminate();
|
|
299
419
|
}
|
|
300
420
|
|
|
301
|
-
// src/Logger.ts
|
|
302
|
-
var Logger = class {
|
|
303
|
-
constructor(name) {
|
|
304
|
-
this.name = name;
|
|
305
|
-
}
|
|
306
|
-
log(...message) {
|
|
307
|
-
const time = process.uptime().toFixed(3);
|
|
308
|
-
console.log(`[${this.name} ${time}]`, ...message);
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
|
|
312
421
|
// src/MicdropServer.ts
|
|
313
422
|
var import_eventemitter32 = require("eventemitter3");
|
|
314
423
|
var import_stream2 = require("stream");
|
|
@@ -879,6 +988,7 @@ async function waitForParams(socket, validate) {
|
|
|
879
988
|
AUTO_SEMANTIC_TURN_PROMPT,
|
|
880
989
|
AUTO_SEMANTIC_TURN_TOOL_NAME,
|
|
881
990
|
Agent,
|
|
991
|
+
FallbackAgent,
|
|
882
992
|
FallbackSTT,
|
|
883
993
|
FallbackTTS,
|
|
884
994
|
Logger,
|
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/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/recorder/MicdropRecorder.ts","../src/stt/STT.ts","../src/stt/MockSTT.ts","../src/stt/FallbackSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/tts/FallbackTTS.ts","../src/waitForParams.ts"],"sourcesContent":["export * from './agent'\nexport * from './errors'\nexport * from './Logger'\nexport * from './MicdropServer'\nexport * from './recorder'\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 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(public 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 { EventEmitter } from 'eventemitter3'\nimport { 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 MicdropServerEvents {\n End: [MicdropCallSummary]\n UserAudio: [Buffer]\n AssistantAudio: [Buffer]\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n}\n\nexport class MicdropServer extends EventEmitter<MicdropServerEvents> {\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 private userSpeechChunks = 0\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n super()\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscriptSTT)\n\n // Setup TTS\n this.config.tts.on('Audio', this.onAudioTTS)\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 // Deferred so consumers (e.g. MicdropRecorder) can subscribe to agent\n // events before the first message is added to the conversation.\n queueMicrotask(() => 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 // Emit End event\n this.emit('End', {\n conversation: this.config.agent.conversation,\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.onUserAudio(message)\n }\n }\n\n private onUserAudio(chunk: Buffer) {\n this.log(`Received chunk (${chunk.byteLength} bytes)`)\n this.currentUserStream?.write(chunk)\n this.userSpeechChunks++\n this.emit('UserAudio', chunk)\n }\n\n private onMute() {\n this.userSpeechChunks = 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.userSpeechChunks = 0\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 const hasNoUserSpeech =\n !this.currentUserStream || this.userSpeechChunks === 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.userSpeechChunks = 0\n\n // If user is not speaking or no chunks were received, skip\n if (hasNoUserSpeech) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\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 onTranscriptSTT = async (transcript: string) => {\n if (!this.config) return\n\n // Skip answer if transcript is empty\n if (transcript === '') {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\n\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 onAudioTTS = (audio: Buffer) => {\n if (!this.socket) return\n this.log(`Send audio chunk (${audio.byteLength} bytes)`)\n this.socket.send(audio)\n this.emit('AssistantAudio', audio)\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 this.config.tts.speak(textStream)\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 type { MicdropServer } from '../MicdropServer'\nimport type { MicdropConversationItem } from '../types'\nimport { Logger } from '../Logger'\n\nexport interface AudioMessage {\n buffer: Buffer\n messageIndex: number\n message: string\n role: 'user' | 'assistant'\n}\n\nexport interface MicdropRecorderEvents {\n AudioMessage: [AudioMessage]\n Complete: [AudioMessage[]]\n}\n\nexport class MicdropRecorder extends EventEmitter<MicdropRecorderEvents> {\n public logger?: Logger\n\n private audioMessages: AudioMessage[] = []\n private currentUserChunks: Buffer[] = []\n private currentAssistantChunks: Buffer[] = []\n private lastUserMessageIndex: number = -1\n private lastAssistantMessageIndex: number = -1\n\n constructor(private server: MicdropServer) {\n super()\n this.setupListeners()\n }\n\n private setupListeners() {\n // Listen to audio events from server\n this.server.on('UserAudio', this.onUserAudio)\n this.server.on('AssistantAudio', this.onAssistantAudio)\n this.server.on('End', this.onEnd)\n\n // Listen to message events from agent\n const agent = this.server.config?.agent\n if (agent) {\n agent.on('Message', this.onMessage)\n }\n }\n\n private onUserAudio = (chunk: Buffer) => {\n // Finalize or discard assistant audio when user starts speaking\n if (this.currentAssistantChunks.length > 0) {\n if (this.lastAssistantMessageIndex >= 0) {\n this.finalizeAssistantAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned assistant audio chunks')\n this.currentAssistantChunks = []\n }\n }\n\n this.log('Recording user audio chunk')\n this.currentUserChunks.push(chunk)\n }\n\n private onAssistantAudio = (chunk: Buffer) => {\n // Finalize or discard user audio when assistant starts speaking\n if (this.currentUserChunks.length > 0) {\n if (this.lastUserMessageIndex >= 0) {\n this.finalizeUserAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned user audio chunks')\n this.currentUserChunks = []\n }\n }\n\n this.log('Recording assistant audio chunk')\n this.currentAssistantChunks.push(chunk)\n }\n\n private onMessage = (message: MicdropConversationItem) => {\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const messageIndex = conversation.length - 1\n\n if (message.role === 'user') {\n this.lastUserMessageIndex = messageIndex\n // User audio might already be complete, finalize if we have chunks\n // Audio chunks arrive BEFORE message, so we finalize when we know the message\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n } else if (message.role === 'assistant') {\n this.lastAssistantMessageIndex = messageIndex\n // Don't finalize assistant audio here - chunks can still arrive after message\n }\n }\n\n private finalizeUserAudio() {\n if (this.currentUserChunks.length === 0) return\n if (this.lastUserMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastUserMessageIndex]\n const buffer = Buffer.concat(this.currentUserChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastUserMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'user',\n }\n\n this.log(\n `Finalized user audio: ${buffer.length} bytes, message index ${this.lastUserMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentUserChunks = []\n this.lastUserMessageIndex = -1\n }\n\n private finalizeAssistantAudio() {\n if (this.currentAssistantChunks.length === 0) return\n if (this.lastAssistantMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastAssistantMessageIndex]\n const buffer = Buffer.concat(this.currentAssistantChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastAssistantMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'assistant',\n }\n\n this.log(\n `Finalized assistant audio: ${buffer.length} bytes, message index ${this.lastAssistantMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentAssistantChunks = []\n this.lastAssistantMessageIndex = -1\n }\n\n private onEnd = () => {\n // Finalize any remaining audio\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n if (this.currentAssistantChunks.length > 0) {\n this.finalizeAssistantAudio()\n }\n\n this.log(`Recording complete: ${this.audioMessages.length} audio messages`)\n this.emit('Complete', this.audioMessages)\n }\n\n public getAudioMessages(): AudioMessage[] {\n return [...this.audioMessages]\n }\n\n public destroy() {\n this.log('Destroyed')\n this.server.off('UserAudio', this.onUserAudio)\n this.server.off('AssistantAudio', this.onAssistantAudio)\n this.server.off('End', this.onEnd)\n\n const agent = this.server.config?.agent\n if (agent) {\n agent.off('Message', this.onMessage)\n }\n\n this.removeAllListeners()\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n}\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface STTEvents {\n Transcript: [string]\n Failed: [Buffer[]]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n public logger?: Logger\n\n // Set stream of audio to transcribe\n abstract transcribe(audioStream: Readable): void\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","import { STT } from './STT'\n\nexport class MockSTT extends STT {\n private i = 0\n\n async transcribe() {\n setTimeout(() => {\n this.emit('Transcript', `User Message ${this.i++}`)\n }, 300)\n }\n}\n","import { PassThrough, Readable } from 'stream'\nimport { STT } from './STT'\nimport { Logger } from '..'\n\nexport interface FallbackSTTOptions {\n factories: Array<() => STT>\n}\n\nexport class FallbackSTT extends STT {\n private stt: STT | null = null\n private sttIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackSTTOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackSTT: No factories provided')\n }\n this.startNextSTT()\n }\n\n transcribe(audioStream: Readable) {\n this.stt?.transcribe(audioStream)\n }\n\n destroy() {\n super.destroy()\n this.stt?.destroy()\n this.stt = null\n this.sttIndex = -1\n }\n\n private startNextSTT() {\n this.sttIndex++\n if (this.sttIndex >= this.options.factories.length) {\n this.sttIndex = 0\n }\n this.stt?.destroy()\n this.stt = this.options.factories[this.sttIndex]()\n this.stt.on('Transcript', this.onTranscript)\n this.stt.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.stt && this.logger) {\n this.stt.logger = new Logger(this.stt.constructor.name)\n }\n }, 0)\n }\n\n private onTranscript = (transcript: string) => {\n this.emit('Transcript', transcript)\n }\n\n private onFailed = (chunks: Buffer[]) => {\n this.log('STT failed, trying next STT')\n this.startNextSTT()\n\n if (chunks.length > 0) {\n this.log('Sending audio chunks again')\n const stream = new PassThrough()\n this.stt?.transcribe(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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 { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface TTSEvents {\n Audio: [Buffer]\n Failed: [string[]]\n}\n\nexport abstract class TTS extends EventEmitter<TTSEvents> {\n public logger?: Logger\n\n abstract speak(textStream: Readable): void\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 { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\nimport { Logger } from '..'\n\nexport interface FallbackTTSOptions {\n factories: Array<() => TTS>\n}\n\nexport class FallbackTTS extends TTS {\n private tts: TTS | null = null\n private ttsIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackTTSOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackTTS: No factories provided')\n }\n this.startNextTTS()\n }\n\n speak(textStream: Readable) {\n this.tts?.speak(textStream)\n }\n\n cancel() {\n this.tts?.cancel()\n }\n\n destroy() {\n super.destroy()\n this.tts?.destroy()\n this.tts = null\n this.ttsIndex = -1\n }\n\n private startNextTTS() {\n this.ttsIndex++\n if (this.ttsIndex >= this.options.factories.length) {\n this.ttsIndex = 0\n }\n this.tts?.destroy()\n this.tts = this.options.factories[this.ttsIndex]()\n this.tts.on('Audio', this.onAudio)\n this.tts.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.tts && this.logger) {\n this.tts.logger = new Logger(this.tts.constructor.name)\n }\n }, 0)\n }\n\n private onAudio = (audio: Buffer) => {\n this.emit('Audio', audio)\n }\n\n private onFailed = (chunks: string[]) => {\n this.log('TTS failed, trying next TTS')\n this.startNextTTS()\n\n if (chunks.length > 0) {\n this.log('Sending text chunks again')\n const stream = new PassThrough()\n this.tts?.speak(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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":["MicdropErrorCode","import_eventemitter3","import_stream","MicdropClientCommands","MicdropServerCommands","import_eventemitter3","import_eventemitter3","import_stream","import_stream","import_eventemitter3","import_stream"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/agent/Agent.ts","../src/agent/tools.ts","../src/Logger.ts","../src/agent/FallbackAgent.ts","../src/agent/MockAgent.ts","../src/errors.ts","../src/MicdropServer.ts","../src/types.ts","../src/recorder/MicdropRecorder.ts","../src/stt/STT.ts","../src/stt/MockSTT.ts","../src/stt/FallbackSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/tts/FallbackTTS.ts","../src/waitForParams.ts"],"sourcesContent":["export * from './agent'\nexport * from './errors'\nexport * from './Logger'\nexport * from './MicdropServer'\nexport * from './recorder'\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 // Emitted when the agent gives up generating an answer (e.g. after exhausting\n // its retries). Used by FallbackAgent to switch to the next agent.\n Failed: []\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 public tools: Tool[]\n\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: (_input, agent) => agent.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: (_input, agent) => agent.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: (_input, agent) => agent.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, this) : {}\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'\nimport type { Agent } from './Agent'\n\nexport interface Tool<Schema extends z.ZodObject = z.ZodObject> {\n name: string\n description: string\n inputSchema?: Schema\n // The executing agent is passed as context so tools stay portable (no binding\n // to a specific agent instance), which lets them be shared between agents.\n execute?: (input: z.infer<Schema>, agent: Agent) => 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","export class Logger {\n constructor(public 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 { PassThrough } from 'stream'\nimport { Logger } from '../Logger'\nimport { MicdropConversationItem, MicdropToolCall } from '../types'\nimport { Agent } from './Agent'\n\nexport interface FallbackAgentOptions {\n factories: Array<() => Agent>\n}\n\nexport class FallbackAgent extends Agent {\n private agent: Agent | null = null\n private agentIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly fallbackOptions: FallbackAgentOptions) {\n super({ systemPrompt: '' })\n if (this.fallbackOptions.factories.length === 0) {\n throw new Error('FallbackAgent: No factories provided')\n }\n this.startNextAgent()\n }\n\n // Delegate extraction to the active agent (extract config lives on children)\n extract(message: string) {\n return this.agent ? this.agent.extract(message) : super.extract(message)\n }\n\n protected async generateAnswer(stream: PassThrough): Promise<void> {\n // Try each agent once (one full rotation) until one answers successfully.\n // The conversation is shared between agents, so the next agent picks up\n // exactly where the failed one stopped.\n for (\n let attempt = 0;\n attempt < this.fallbackOptions.factories.length;\n attempt++\n ) {\n const agent = this.agent\n if (!agent) return\n\n let failed = false\n const onFailed = () => {\n failed = true\n }\n agent.once('Failed', onFailed)\n\n try {\n await this.pipeAnswer(agent, stream)\n } finally {\n agent.off('Failed', onFailed)\n }\n\n if (!failed) return\n\n this.log('Agent failed, trying next agent')\n this.startNextAgent()\n }\n\n // Every agent failed within this rotation: report it so an outer consumer\n // (e.g. a wrapping FallbackAgent) can react.\n this.log('All agents failed')\n this.emit('Failed')\n }\n\n cancel() {\n this.agent?.cancel()\n }\n\n destroy() {\n super.destroy()\n this.agent?.destroy()\n this.agent = null\n this.agentIndex = -1\n }\n\n // Run the child agent and forward its answer chunks to our own stream\n private pipeAnswer(agent: Agent, stream: PassThrough): Promise<void> {\n return new Promise((resolve) => {\n const answerStream = agent.answer()\n answerStream.on('data', (chunk) => {\n if (stream.writable) {\n stream.write(chunk)\n }\n })\n answerStream.on('end', resolve)\n answerStream.on('error', resolve)\n })\n }\n\n private startNextAgent() {\n this.agentIndex++\n if (this.agentIndex >= this.fallbackOptions.factories.length) {\n this.agentIndex = 0\n }\n\n const previousAgent = this.agent\n const isFirstAgent = previousAgent === null\n const agent = this.fallbackOptions.factories[this.agentIndex]()\n this.agent = agent\n\n // Share the conversation and tools between the fallback and the child agent.\n // Both are now portable (tools no longer bind to a specific instance), so a\n // single reference is shared, exactly like the conversation.\n if (isFirstAgent) {\n // Adopt the first agent's conversation and tools (keeps its system prompt)\n this.conversation = agent.conversation\n this.tools = agent.tools\n } else {\n // Keep the accumulated history, but use the new agent's system prompt\n if (agent.conversation[0]?.role === 'system') {\n this.conversation[0] = agent.conversation[0]\n }\n agent.conversation = this.conversation\n agent.tools = this.tools\n }\n\n // Forward events from the child agent\n agent.on('Message', this.onMessage)\n agent.on('CancelLastUserMessage', this.onCancelLastUserMessage)\n agent.on('SkipAnswer', this.onSkipAnswer)\n agent.on('EndCall', this.onEndCall)\n agent.on('ToolCall', this.onToolCall)\n\n // Destroy the previous agent (after moving the conversation over)\n previousAgent?.destroy()\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.agent && this.logger) {\n this.agent.logger = new Logger(this.agent.constructor.name)\n }\n }, 0)\n }\n\n private onMessage = (message: MicdropConversationItem) => {\n this.emit('Message', message)\n }\n\n private onCancelLastUserMessage = () => {\n this.emit('CancelLastUserMessage')\n }\n\n private onSkipAnswer = () => {\n this.emit('SkipAnswer')\n }\n\n private onEndCall = () => {\n this.emit('EndCall')\n }\n\n private onToolCall = (toolCall: MicdropToolCall) => {\n this.emit('ToolCall', toolCall)\n }\n}\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 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","import { EventEmitter } from 'eventemitter3'\nimport { 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 MicdropServerEvents {\n End: [MicdropCallSummary]\n UserAudio: [Buffer]\n AssistantAudio: [Buffer]\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n}\n\nexport class MicdropServer extends EventEmitter<MicdropServerEvents> {\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 private userSpeechChunks = 0\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n super()\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscriptSTT)\n\n // Setup TTS\n this.config.tts.on('Audio', this.onAudioTTS)\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 // Deferred so consumers (e.g. MicdropRecorder) can subscribe to agent\n // events before the first message is added to the conversation.\n queueMicrotask(() => 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 // Emit End event\n this.emit('End', {\n conversation: this.config.agent.conversation,\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.onUserAudio(message)\n }\n }\n\n private onUserAudio(chunk: Buffer) {\n this.log(`Received chunk (${chunk.byteLength} bytes)`)\n this.currentUserStream?.write(chunk)\n this.userSpeechChunks++\n this.emit('UserAudio', chunk)\n }\n\n private onMute() {\n this.userSpeechChunks = 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.userSpeechChunks = 0\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 const hasNoUserSpeech =\n !this.currentUserStream || this.userSpeechChunks === 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.userSpeechChunks = 0\n\n // If user is not speaking or no chunks were received, skip\n if (hasNoUserSpeech) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\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 onTranscriptSTT = async (transcript: string) => {\n if (!this.config) return\n\n // Skip answer if transcript is empty\n if (transcript === '') {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\n\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 onAudioTTS = (audio: Buffer) => {\n if (!this.socket) return\n this.log(`Send audio chunk (${audio.byteLength} bytes)`)\n this.socket.send(audio)\n this.emit('AssistantAudio', audio)\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 this.config.tts.speak(textStream)\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 type { MicdropServer } from '../MicdropServer'\nimport type { MicdropConversationItem } from '../types'\nimport { Logger } from '../Logger'\n\nexport interface AudioMessage {\n buffer: Buffer\n messageIndex: number\n message: string\n role: 'user' | 'assistant'\n}\n\nexport interface MicdropRecorderEvents {\n AudioMessage: [AudioMessage]\n Complete: [AudioMessage[]]\n}\n\nexport class MicdropRecorder extends EventEmitter<MicdropRecorderEvents> {\n public logger?: Logger\n\n private audioMessages: AudioMessage[] = []\n private currentUserChunks: Buffer[] = []\n private currentAssistantChunks: Buffer[] = []\n private lastUserMessageIndex: number = -1\n private lastAssistantMessageIndex: number = -1\n\n constructor(private server: MicdropServer) {\n super()\n this.setupListeners()\n }\n\n private setupListeners() {\n // Listen to audio events from server\n this.server.on('UserAudio', this.onUserAudio)\n this.server.on('AssistantAudio', this.onAssistantAudio)\n this.server.on('End', this.onEnd)\n\n // Listen to message events from agent\n const agent = this.server.config?.agent\n if (agent) {\n agent.on('Message', this.onMessage)\n }\n }\n\n private onUserAudio = (chunk: Buffer) => {\n // Finalize or discard assistant audio when user starts speaking\n if (this.currentAssistantChunks.length > 0) {\n if (this.lastAssistantMessageIndex >= 0) {\n this.finalizeAssistantAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned assistant audio chunks')\n this.currentAssistantChunks = []\n }\n }\n\n this.log('Recording user audio chunk')\n this.currentUserChunks.push(chunk)\n }\n\n private onAssistantAudio = (chunk: Buffer) => {\n // Finalize or discard user audio when assistant starts speaking\n if (this.currentUserChunks.length > 0) {\n if (this.lastUserMessageIndex >= 0) {\n this.finalizeUserAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned user audio chunks')\n this.currentUserChunks = []\n }\n }\n\n this.log('Recording assistant audio chunk')\n this.currentAssistantChunks.push(chunk)\n }\n\n private onMessage = (message: MicdropConversationItem) => {\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const messageIndex = conversation.length - 1\n\n if (message.role === 'user') {\n this.lastUserMessageIndex = messageIndex\n // User audio might already be complete, finalize if we have chunks\n // Audio chunks arrive BEFORE message, so we finalize when we know the message\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n } else if (message.role === 'assistant') {\n this.lastAssistantMessageIndex = messageIndex\n // Don't finalize assistant audio here - chunks can still arrive after message\n }\n }\n\n private finalizeUserAudio() {\n if (this.currentUserChunks.length === 0) return\n if (this.lastUserMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastUserMessageIndex]\n const buffer = Buffer.concat(this.currentUserChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastUserMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'user',\n }\n\n this.log(\n `Finalized user audio: ${buffer.length} bytes, message index ${this.lastUserMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentUserChunks = []\n this.lastUserMessageIndex = -1\n }\n\n private finalizeAssistantAudio() {\n if (this.currentAssistantChunks.length === 0) return\n if (this.lastAssistantMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastAssistantMessageIndex]\n const buffer = Buffer.concat(this.currentAssistantChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastAssistantMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'assistant',\n }\n\n this.log(\n `Finalized assistant audio: ${buffer.length} bytes, message index ${this.lastAssistantMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentAssistantChunks = []\n this.lastAssistantMessageIndex = -1\n }\n\n private onEnd = () => {\n // Finalize any remaining audio\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n if (this.currentAssistantChunks.length > 0) {\n this.finalizeAssistantAudio()\n }\n\n this.log(`Recording complete: ${this.audioMessages.length} audio messages`)\n this.emit('Complete', this.audioMessages)\n }\n\n public getAudioMessages(): AudioMessage[] {\n return [...this.audioMessages]\n }\n\n public destroy() {\n this.log('Destroyed')\n this.server.off('UserAudio', this.onUserAudio)\n this.server.off('AssistantAudio', this.onAssistantAudio)\n this.server.off('End', this.onEnd)\n\n const agent = this.server.config?.agent\n if (agent) {\n agent.off('Message', this.onMessage)\n }\n\n this.removeAllListeners()\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n}\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface STTEvents {\n Transcript: [string]\n Failed: [Buffer[]]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n public logger?: Logger\n\n // Set stream of audio to transcribe\n abstract transcribe(audioStream: Readable): void\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","import { STT } from './STT'\n\nexport class MockSTT extends STT {\n private i = 0\n\n async transcribe() {\n setTimeout(() => {\n this.emit('Transcript', `User Message ${this.i++}`)\n }, 300)\n }\n}\n","import { PassThrough, Readable } from 'stream'\nimport { STT } from './STT'\nimport { Logger } from '..'\n\nexport interface FallbackSTTOptions {\n factories: Array<() => STT>\n}\n\nexport class FallbackSTT extends STT {\n private stt: STT | null = null\n private sttIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackSTTOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackSTT: No factories provided')\n }\n this.startNextSTT()\n }\n\n transcribe(audioStream: Readable) {\n this.stt?.transcribe(audioStream)\n }\n\n destroy() {\n super.destroy()\n this.stt?.destroy()\n this.stt = null\n this.sttIndex = -1\n }\n\n private startNextSTT() {\n this.sttIndex++\n if (this.sttIndex >= this.options.factories.length) {\n this.sttIndex = 0\n }\n this.stt?.destroy()\n this.stt = this.options.factories[this.sttIndex]()\n this.stt.on('Transcript', this.onTranscript)\n this.stt.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.stt && this.logger) {\n this.stt.logger = new Logger(this.stt.constructor.name)\n }\n }, 0)\n }\n\n private onTranscript = (transcript: string) => {\n this.emit('Transcript', transcript)\n }\n\n private onFailed = (chunks: Buffer[]) => {\n this.log('STT failed, trying next STT')\n this.startNextSTT()\n\n if (chunks.length > 0) {\n this.log('Sending audio chunks again')\n const stream = new PassThrough()\n this.stt?.transcribe(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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 { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface TTSEvents {\n Audio: [Buffer]\n Failed: [string[]]\n}\n\nexport abstract class TTS extends EventEmitter<TTSEvents> {\n public logger?: Logger\n\n abstract speak(textStream: Readable): void\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 { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\nimport { Logger } from '..'\n\nexport interface FallbackTTSOptions {\n factories: Array<() => TTS>\n}\n\nexport class FallbackTTS extends TTS {\n private tts: TTS | null = null\n private ttsIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackTTSOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackTTS: No factories provided')\n }\n this.startNextTTS()\n }\n\n speak(textStream: Readable) {\n this.tts?.speak(textStream)\n }\n\n cancel() {\n this.tts?.cancel()\n }\n\n destroy() {\n super.destroy()\n this.tts?.destroy()\n this.tts = null\n this.ttsIndex = -1\n }\n\n private startNextTTS() {\n this.ttsIndex++\n if (this.ttsIndex >= this.options.factories.length) {\n this.ttsIndex = 0\n }\n this.tts?.destroy()\n this.tts = this.options.factories[this.ttsIndex]()\n this.tts.on('Audio', this.onAudio)\n this.tts.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.tts && this.logger) {\n this.tts.logger = new Logger(this.tts.constructor.name)\n }\n }, 0)\n }\n\n private onAudio = (audio: Buffer) => {\n this.emit('Audio', audio)\n }\n\n private onFailed = (chunks: string[]) => {\n this.log('TTS failed, trying next TTS')\n this.startNextTTS()\n\n if (chunks.length > 0) {\n this.log('Sending text chunks again')\n const stream = new PassThrough()\n this.tts?.speak(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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":["MicdropErrorCode","import_eventemitter3","import_stream","MicdropClientCommands","MicdropServerCommands","import_eventemitter3","import_eventemitter3","import_stream","import_stream","import_eventemitter3","import_stream"]}
|
package/dist/index.mjs
CHANGED
|
@@ -95,7 +95,7 @@ var Agent = class extends EventEmitter {
|
|
|
95
95
|
tools.push({
|
|
96
96
|
name: AUTO_END_CALL_TOOL_NAME,
|
|
97
97
|
description: typeof this.options.autoEndCall === "string" ? this.options.autoEndCall : AUTO_END_CALL_PROMPT,
|
|
98
|
-
execute: () =>
|
|
98
|
+
execute: (_input, agent) => agent.endCall()
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
if (this.options.autoSemanticTurn) {
|
|
@@ -103,7 +103,7 @@ var Agent = class extends EventEmitter {
|
|
|
103
103
|
name: AUTO_SEMANTIC_TURN_TOOL_NAME,
|
|
104
104
|
description: typeof this.options.autoSemanticTurn === "string" ? this.options.autoSemanticTurn : AUTO_SEMANTIC_TURN_PROMPT,
|
|
105
105
|
skipAnswer: true,
|
|
106
|
-
execute: () =>
|
|
106
|
+
execute: (_input, agent) => agent.skipAnswer()
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
if (this.options.autoIgnoreUserNoise) {
|
|
@@ -111,7 +111,7 @@ var Agent = class extends EventEmitter {
|
|
|
111
111
|
name: AUTO_IGNORE_USER_NOISE_TOOL_NAME,
|
|
112
112
|
description: typeof this.options.autoIgnoreUserNoise === "string" ? this.options.autoIgnoreUserNoise : AUTO_IGNORE_USER_NOISE_PROMPT,
|
|
113
113
|
skipAnswer: true,
|
|
114
|
-
execute: () =>
|
|
114
|
+
execute: (_input, agent) => agent.cancelLastUserMessage()
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
return tools;
|
|
@@ -125,7 +125,7 @@ var Agent = class extends EventEmitter {
|
|
|
125
125
|
this.log("Executing tool:", toolCall.toolName, toolCall.parameters);
|
|
126
126
|
this.addToolMessage(toolCall);
|
|
127
127
|
const parameters = JSON.parse(toolCall.parameters);
|
|
128
|
-
const output = tool.execute ? await tool.execute(parameters) : {};
|
|
128
|
+
const output = tool.execute ? await tool.execute(parameters, this) : {};
|
|
129
129
|
this.addToolMessage({
|
|
130
130
|
role: "tool_result",
|
|
131
131
|
toolCallId: toolCall.toolCallId,
|
|
@@ -202,6 +202,125 @@ var Agent = class extends EventEmitter {
|
|
|
202
202
|
}
|
|
203
203
|
};
|
|
204
204
|
|
|
205
|
+
// src/Logger.ts
|
|
206
|
+
var Logger = class {
|
|
207
|
+
constructor(name) {
|
|
208
|
+
this.name = name;
|
|
209
|
+
}
|
|
210
|
+
log(...message) {
|
|
211
|
+
const time = process.uptime().toFixed(3);
|
|
212
|
+
console.log(`[${this.name} ${time}]`, ...message);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// src/agent/FallbackAgent.ts
|
|
217
|
+
var FallbackAgent = class extends Agent {
|
|
218
|
+
// Start at -1 because we need to increment it before using it
|
|
219
|
+
constructor(fallbackOptions) {
|
|
220
|
+
super({ systemPrompt: "" });
|
|
221
|
+
this.fallbackOptions = fallbackOptions;
|
|
222
|
+
this.agent = null;
|
|
223
|
+
this.agentIndex = -1;
|
|
224
|
+
this.onMessage = (message) => {
|
|
225
|
+
this.emit("Message", message);
|
|
226
|
+
};
|
|
227
|
+
this.onCancelLastUserMessage = () => {
|
|
228
|
+
this.emit("CancelLastUserMessage");
|
|
229
|
+
};
|
|
230
|
+
this.onSkipAnswer = () => {
|
|
231
|
+
this.emit("SkipAnswer");
|
|
232
|
+
};
|
|
233
|
+
this.onEndCall = () => {
|
|
234
|
+
this.emit("EndCall");
|
|
235
|
+
};
|
|
236
|
+
this.onToolCall = (toolCall) => {
|
|
237
|
+
this.emit("ToolCall", toolCall);
|
|
238
|
+
};
|
|
239
|
+
if (this.fallbackOptions.factories.length === 0) {
|
|
240
|
+
throw new Error("FallbackAgent: No factories provided");
|
|
241
|
+
}
|
|
242
|
+
this.startNextAgent();
|
|
243
|
+
}
|
|
244
|
+
// Delegate extraction to the active agent (extract config lives on children)
|
|
245
|
+
extract(message) {
|
|
246
|
+
return this.agent ? this.agent.extract(message) : super.extract(message);
|
|
247
|
+
}
|
|
248
|
+
async generateAnswer(stream) {
|
|
249
|
+
for (let attempt = 0; attempt < this.fallbackOptions.factories.length; attempt++) {
|
|
250
|
+
const agent = this.agent;
|
|
251
|
+
if (!agent) return;
|
|
252
|
+
let failed = false;
|
|
253
|
+
const onFailed = () => {
|
|
254
|
+
failed = true;
|
|
255
|
+
};
|
|
256
|
+
agent.once("Failed", onFailed);
|
|
257
|
+
try {
|
|
258
|
+
await this.pipeAnswer(agent, stream);
|
|
259
|
+
} finally {
|
|
260
|
+
agent.off("Failed", onFailed);
|
|
261
|
+
}
|
|
262
|
+
if (!failed) return;
|
|
263
|
+
this.log("Agent failed, trying next agent");
|
|
264
|
+
this.startNextAgent();
|
|
265
|
+
}
|
|
266
|
+
this.log("All agents failed");
|
|
267
|
+
this.emit("Failed");
|
|
268
|
+
}
|
|
269
|
+
cancel() {
|
|
270
|
+
this.agent?.cancel();
|
|
271
|
+
}
|
|
272
|
+
destroy() {
|
|
273
|
+
super.destroy();
|
|
274
|
+
this.agent?.destroy();
|
|
275
|
+
this.agent = null;
|
|
276
|
+
this.agentIndex = -1;
|
|
277
|
+
}
|
|
278
|
+
// Run the child agent and forward its answer chunks to our own stream
|
|
279
|
+
pipeAnswer(agent, stream) {
|
|
280
|
+
return new Promise((resolve) => {
|
|
281
|
+
const answerStream = agent.answer();
|
|
282
|
+
answerStream.on("data", (chunk) => {
|
|
283
|
+
if (stream.writable) {
|
|
284
|
+
stream.write(chunk);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
answerStream.on("end", resolve);
|
|
288
|
+
answerStream.on("error", resolve);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
startNextAgent() {
|
|
292
|
+
this.agentIndex++;
|
|
293
|
+
if (this.agentIndex >= this.fallbackOptions.factories.length) {
|
|
294
|
+
this.agentIndex = 0;
|
|
295
|
+
}
|
|
296
|
+
const previousAgent = this.agent;
|
|
297
|
+
const isFirstAgent = previousAgent === null;
|
|
298
|
+
const agent = this.fallbackOptions.factories[this.agentIndex]();
|
|
299
|
+
this.agent = agent;
|
|
300
|
+
if (isFirstAgent) {
|
|
301
|
+
this.conversation = agent.conversation;
|
|
302
|
+
this.tools = agent.tools;
|
|
303
|
+
} else {
|
|
304
|
+
if (agent.conversation[0]?.role === "system") {
|
|
305
|
+
this.conversation[0] = agent.conversation[0];
|
|
306
|
+
}
|
|
307
|
+
agent.conversation = this.conversation;
|
|
308
|
+
agent.tools = this.tools;
|
|
309
|
+
}
|
|
310
|
+
agent.on("Message", this.onMessage);
|
|
311
|
+
agent.on("CancelLastUserMessage", this.onCancelLastUserMessage);
|
|
312
|
+
agent.on("SkipAnswer", this.onSkipAnswer);
|
|
313
|
+
agent.on("EndCall", this.onEndCall);
|
|
314
|
+
agent.on("ToolCall", this.onToolCall);
|
|
315
|
+
previousAgent?.destroy();
|
|
316
|
+
setTimeout(() => {
|
|
317
|
+
if (this.agent && this.logger) {
|
|
318
|
+
this.agent.logger = new Logger(this.agent.constructor.name);
|
|
319
|
+
}
|
|
320
|
+
}, 0);
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
205
324
|
// src/agent/MockAgent.ts
|
|
206
325
|
var MockAgent = class extends Agent {
|
|
207
326
|
constructor() {
|
|
@@ -240,17 +359,6 @@ function handleError(socket, error) {
|
|
|
240
359
|
socket.terminate();
|
|
241
360
|
}
|
|
242
361
|
|
|
243
|
-
// src/Logger.ts
|
|
244
|
-
var Logger = class {
|
|
245
|
-
constructor(name) {
|
|
246
|
-
this.name = name;
|
|
247
|
-
}
|
|
248
|
-
log(...message) {
|
|
249
|
-
const time = process.uptime().toFixed(3);
|
|
250
|
-
console.log(`[${this.name} ${time}]`, ...message);
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
362
|
// src/MicdropServer.ts
|
|
255
363
|
import { EventEmitter as EventEmitter2 } from "eventemitter3";
|
|
256
364
|
import { PassThrough as PassThrough2 } from "stream";
|
|
@@ -820,6 +928,7 @@ export {
|
|
|
820
928
|
AUTO_SEMANTIC_TURN_PROMPT,
|
|
821
929
|
AUTO_SEMANTIC_TURN_TOOL_NAME,
|
|
822
930
|
Agent,
|
|
931
|
+
FallbackAgent,
|
|
823
932
|
FallbackSTT,
|
|
824
933
|
FallbackTTS,
|
|
825
934
|
Logger,
|
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/errors.ts","../src/Logger.ts","../src/MicdropServer.ts","../src/types.ts","../src/recorder/MicdropRecorder.ts","../src/stt/STT.ts","../src/stt/MockSTT.ts","../src/stt/FallbackSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/tts/FallbackTTS.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 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(public 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 { EventEmitter } from 'eventemitter3'\nimport { 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 MicdropServerEvents {\n End: [MicdropCallSummary]\n UserAudio: [Buffer]\n AssistantAudio: [Buffer]\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n}\n\nexport class MicdropServer extends EventEmitter<MicdropServerEvents> {\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 private userSpeechChunks = 0\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n super()\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscriptSTT)\n\n // Setup TTS\n this.config.tts.on('Audio', this.onAudioTTS)\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 // Deferred so consumers (e.g. MicdropRecorder) can subscribe to agent\n // events before the first message is added to the conversation.\n queueMicrotask(() => 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 // Emit End event\n this.emit('End', {\n conversation: this.config.agent.conversation,\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.onUserAudio(message)\n }\n }\n\n private onUserAudio(chunk: Buffer) {\n this.log(`Received chunk (${chunk.byteLength} bytes)`)\n this.currentUserStream?.write(chunk)\n this.userSpeechChunks++\n this.emit('UserAudio', chunk)\n }\n\n private onMute() {\n this.userSpeechChunks = 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.userSpeechChunks = 0\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 const hasNoUserSpeech =\n !this.currentUserStream || this.userSpeechChunks === 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.userSpeechChunks = 0\n\n // If user is not speaking or no chunks were received, skip\n if (hasNoUserSpeech) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\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 onTranscriptSTT = async (transcript: string) => {\n if (!this.config) return\n\n // Skip answer if transcript is empty\n if (transcript === '') {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\n\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 onAudioTTS = (audio: Buffer) => {\n if (!this.socket) return\n this.log(`Send audio chunk (${audio.byteLength} bytes)`)\n this.socket.send(audio)\n this.emit('AssistantAudio', audio)\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 this.config.tts.speak(textStream)\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 type { MicdropServer } from '../MicdropServer'\nimport type { MicdropConversationItem } from '../types'\nimport { Logger } from '../Logger'\n\nexport interface AudioMessage {\n buffer: Buffer\n messageIndex: number\n message: string\n role: 'user' | 'assistant'\n}\n\nexport interface MicdropRecorderEvents {\n AudioMessage: [AudioMessage]\n Complete: [AudioMessage[]]\n}\n\nexport class MicdropRecorder extends EventEmitter<MicdropRecorderEvents> {\n public logger?: Logger\n\n private audioMessages: AudioMessage[] = []\n private currentUserChunks: Buffer[] = []\n private currentAssistantChunks: Buffer[] = []\n private lastUserMessageIndex: number = -1\n private lastAssistantMessageIndex: number = -1\n\n constructor(private server: MicdropServer) {\n super()\n this.setupListeners()\n }\n\n private setupListeners() {\n // Listen to audio events from server\n this.server.on('UserAudio', this.onUserAudio)\n this.server.on('AssistantAudio', this.onAssistantAudio)\n this.server.on('End', this.onEnd)\n\n // Listen to message events from agent\n const agent = this.server.config?.agent\n if (agent) {\n agent.on('Message', this.onMessage)\n }\n }\n\n private onUserAudio = (chunk: Buffer) => {\n // Finalize or discard assistant audio when user starts speaking\n if (this.currentAssistantChunks.length > 0) {\n if (this.lastAssistantMessageIndex >= 0) {\n this.finalizeAssistantAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned assistant audio chunks')\n this.currentAssistantChunks = []\n }\n }\n\n this.log('Recording user audio chunk')\n this.currentUserChunks.push(chunk)\n }\n\n private onAssistantAudio = (chunk: Buffer) => {\n // Finalize or discard user audio when assistant starts speaking\n if (this.currentUserChunks.length > 0) {\n if (this.lastUserMessageIndex >= 0) {\n this.finalizeUserAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned user audio chunks')\n this.currentUserChunks = []\n }\n }\n\n this.log('Recording assistant audio chunk')\n this.currentAssistantChunks.push(chunk)\n }\n\n private onMessage = (message: MicdropConversationItem) => {\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const messageIndex = conversation.length - 1\n\n if (message.role === 'user') {\n this.lastUserMessageIndex = messageIndex\n // User audio might already be complete, finalize if we have chunks\n // Audio chunks arrive BEFORE message, so we finalize when we know the message\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n } else if (message.role === 'assistant') {\n this.lastAssistantMessageIndex = messageIndex\n // Don't finalize assistant audio here - chunks can still arrive after message\n }\n }\n\n private finalizeUserAudio() {\n if (this.currentUserChunks.length === 0) return\n if (this.lastUserMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastUserMessageIndex]\n const buffer = Buffer.concat(this.currentUserChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastUserMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'user',\n }\n\n this.log(\n `Finalized user audio: ${buffer.length} bytes, message index ${this.lastUserMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentUserChunks = []\n this.lastUserMessageIndex = -1\n }\n\n private finalizeAssistantAudio() {\n if (this.currentAssistantChunks.length === 0) return\n if (this.lastAssistantMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastAssistantMessageIndex]\n const buffer = Buffer.concat(this.currentAssistantChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastAssistantMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'assistant',\n }\n\n this.log(\n `Finalized assistant audio: ${buffer.length} bytes, message index ${this.lastAssistantMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentAssistantChunks = []\n this.lastAssistantMessageIndex = -1\n }\n\n private onEnd = () => {\n // Finalize any remaining audio\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n if (this.currentAssistantChunks.length > 0) {\n this.finalizeAssistantAudio()\n }\n\n this.log(`Recording complete: ${this.audioMessages.length} audio messages`)\n this.emit('Complete', this.audioMessages)\n }\n\n public getAudioMessages(): AudioMessage[] {\n return [...this.audioMessages]\n }\n\n public destroy() {\n this.log('Destroyed')\n this.server.off('UserAudio', this.onUserAudio)\n this.server.off('AssistantAudio', this.onAssistantAudio)\n this.server.off('End', this.onEnd)\n\n const agent = this.server.config?.agent\n if (agent) {\n agent.off('Message', this.onMessage)\n }\n\n this.removeAllListeners()\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n}\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface STTEvents {\n Transcript: [string]\n Failed: [Buffer[]]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n public logger?: Logger\n\n // Set stream of audio to transcribe\n abstract transcribe(audioStream: Readable): void\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","import { STT } from './STT'\n\nexport class MockSTT extends STT {\n private i = 0\n\n async transcribe() {\n setTimeout(() => {\n this.emit('Transcript', `User Message ${this.i++}`)\n }, 300)\n }\n}\n","import { PassThrough, Readable } from 'stream'\nimport { STT } from './STT'\nimport { Logger } from '..'\n\nexport interface FallbackSTTOptions {\n factories: Array<() => STT>\n}\n\nexport class FallbackSTT extends STT {\n private stt: STT | null = null\n private sttIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackSTTOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackSTT: No factories provided')\n }\n this.startNextSTT()\n }\n\n transcribe(audioStream: Readable) {\n this.stt?.transcribe(audioStream)\n }\n\n destroy() {\n super.destroy()\n this.stt?.destroy()\n this.stt = null\n this.sttIndex = -1\n }\n\n private startNextSTT() {\n this.sttIndex++\n if (this.sttIndex >= this.options.factories.length) {\n this.sttIndex = 0\n }\n this.stt?.destroy()\n this.stt = this.options.factories[this.sttIndex]()\n this.stt.on('Transcript', this.onTranscript)\n this.stt.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.stt && this.logger) {\n this.stt.logger = new Logger(this.stt.constructor.name)\n }\n }, 0)\n }\n\n private onTranscript = (transcript: string) => {\n this.emit('Transcript', transcript)\n }\n\n private onFailed = (chunks: Buffer[]) => {\n this.log('STT failed, trying next STT')\n this.startNextSTT()\n\n if (chunks.length > 0) {\n this.log('Sending audio chunks again')\n const stream = new PassThrough()\n this.stt?.transcribe(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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 { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface TTSEvents {\n Audio: [Buffer]\n Failed: [string[]]\n}\n\nexport abstract class TTS extends EventEmitter<TTSEvents> {\n public logger?: Logger\n\n abstract speak(textStream: Readable): void\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 { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\nimport { Logger } from '..'\n\nexport interface FallbackTTSOptions {\n factories: Array<() => TTS>\n}\n\nexport class FallbackTTS extends TTS {\n private tts: TTS | null = null\n private ttsIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackTTSOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackTTS: No factories provided')\n }\n this.startNextTTS()\n }\n\n speak(textStream: Readable) {\n this.tts?.speak(textStream)\n }\n\n cancel() {\n this.tts?.cancel()\n }\n\n destroy() {\n super.destroy()\n this.tts?.destroy()\n this.tts = null\n this.ttsIndex = -1\n }\n\n private startNextTTS() {\n this.ttsIndex++\n if (this.ttsIndex >= this.options.factories.length) {\n this.ttsIndex = 0\n }\n this.tts?.destroy()\n this.tts = this.options.factories[this.ttsIndex]()\n this.tts.on('Audio', this.onAudio)\n this.tts.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.tts && this.logger) {\n this.tts.logger = new Logger(this.tts.constructor.name)\n }\n }, 0)\n }\n\n private onAudio = (audio: Buffer) => {\n this.emit('Audio', audio)\n }\n\n private onFailed = (chunks: string[]) => {\n this.log('TTS failed, trying next TTS')\n this.startNextTTS()\n\n if (chunks.length > 0) {\n this.log('Sending text chunks again')\n const stream = new PassThrough()\n this.tts?.speak(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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,SAAS,oBAAoB;AAC7B,SAAS,mBAAuC;;;ACUzC,IAAM,0BAA0B;AAChC,IAAM,uBACX;AAEK,IAAM,+BAA+B;AACrC,IAAM,4BACX;AAEK,IAAM,mCAAmC;AACzC,IAAM,gCACX;;;ADoDK,IAAe,QAAf,cAEG,aAA0B;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,YAAY;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;;;ACfO,IAAK,mBAAL,kBAAKA,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,YAAmB,MAAc;AAAd;AAAA,EAAe;AAAA,EAElC,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,SAAS,gBAAAC,qBAAoB;AAC7B,SAAiB,eAAAC,oBAA6B;;;ACDvC,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;;;ADsBL,IAAM,gBAAN,cAA4BC,cAAkC;AAAA,EAgBnE,YAAY,QAAmB,QAAuB;AACpD,UAAM;AAhBR,SAAO,SAA2B;AAClC,SAAO,SAA+B;AAGtC,SAAQ,YAAY,KAAK,IAAI;AAI7B;AAAA,SAAQ,iBAA6C,CAAC;AACtD,SAAQ,oBAAoB;AAI5B,SAAQ,mBAAmB;AAgF3B,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,KAAK,OAAO;AAAA,QACf,cAAc,KAAK,OAAO,MAAM;AAAA,QAChC;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,YAAY,OAAO;AAAA,MAC1B;AAAA,IACF;AAoDA,SAAQ,kBAAkB,OAAO,eAAuB;AACtD,UAAI,CAAC,KAAK,OAAQ;AAGlB,UAAI,eAAe,IAAI;AACrB,aAAK,QAAQ,kCAAqC;AAClD;AAAA,MACF;AAEA,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;AAEA,SAAQ,aAAa,CAAC,UAAkB;AACtC,UAAI,CAAC,KAAK,OAAQ;AAClB,WAAK,IAAI,qBAAqB,MAAM,UAAU,SAAS;AACvD,WAAK,OAAO,KAAK,KAAK;AACtB,WAAK,KAAK,kBAAkB,KAAK;AAAA,IACnC;AA1ME,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,IAAI,cAAc;AAGvB,SAAK,OAAO,IAAI,GAAG,cAAc,KAAK,eAAe;AAGrD,SAAK,OAAO,IAAI,GAAG,SAAS,KAAK,UAAU;AAG3C,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;AAKA,mBAAe,MAAM,KAAK,iBAAiB,CAAC;AAG5C,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,EAqDQ,YAAY,OAAe;AACjC,SAAK,IAAI,mBAAmB,MAAM,UAAU,SAAS;AACrD,SAAK,mBAAmB,MAAM,KAAK;AACnC,SAAK;AACL,SAAK,KAAK,aAAa,KAAK;AAAA,EAC9B;AAAA,EAEQ,SAAS;AACf,SAAK,mBAAmB;AACxB,SAAK,mBAAmB,IAAI;AAC5B,SAAK,oBAAoB;AACzB,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,kBAAkB;AACxB,QAAI,CAAC,KAAK,OAAQ;AAClB,SAAK,mBAAmB;AACxB,SAAK,mBAAmB,IAAI;AAC5B,SAAK,oBAAoB,IAAIC,aAAY;AACzC,SAAK,OAAO,IAAI,WAAW,KAAK,iBAAiB;AACjD,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,iBAAiB;AACvB,UAAM,kBACJ,CAAC,KAAK,qBAAqB,KAAK,qBAAqB;AACvD,SAAK,mBAAmB,IAAI;AAC5B,SAAK,oBAAoB;AACzB,SAAK,mBAAmB;AAGxB,QAAI,iBAAiB;AACnB,WAAK,QAAQ,kCAAqC;AAClD;AAAA,IACF;AAEA,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,EA6BQ,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,IAAIA,aAAY;AAC/B,aAAO,MAAM,OAAO;AACpB,aAAO,IAAI;AACX,mBAAa;AAAA,IACf,OAAO;AACL,mBAAa;AAAA,IACf;AAGA,SAAK,OAAO,IAAI,MAAM,UAAU;AAAA,EAClC;AACF;;;AEhUA,SAAS,gBAAAC,qBAAoB;AAiBtB,IAAM,kBAAN,cAA8BA,cAAoC;AAAA,EASvE,YAAoB,QAAuB;AACzC,UAAM;AADY;AANpB,SAAQ,gBAAgC,CAAC;AACzC,SAAQ,oBAA8B,CAAC;AACvC,SAAQ,yBAAmC,CAAC;AAC5C,SAAQ,uBAA+B;AACvC,SAAQ,4BAAoC;AAoB5C,SAAQ,cAAc,CAAC,UAAkB;AAEvC,UAAI,KAAK,uBAAuB,SAAS,GAAG;AAC1C,YAAI,KAAK,6BAA6B,GAAG;AACvC,eAAK,uBAAuB;AAAA,QAC9B,OAAO;AAEL,eAAK,IAAI,4CAA4C;AACrD,eAAK,yBAAyB,CAAC;AAAA,QACjC;AAAA,MACF;AAEA,WAAK,IAAI,4BAA4B;AACrC,WAAK,kBAAkB,KAAK,KAAK;AAAA,IACnC;AAEA,SAAQ,mBAAmB,CAAC,UAAkB;AAE5C,UAAI,KAAK,kBAAkB,SAAS,GAAG;AACrC,YAAI,KAAK,wBAAwB,GAAG;AAClC,eAAK,kBAAkB;AAAA,QACzB,OAAO;AAEL,eAAK,IAAI,uCAAuC;AAChD,eAAK,oBAAoB,CAAC;AAAA,QAC5B;AAAA,MACF;AAEA,WAAK,IAAI,iCAAiC;AAC1C,WAAK,uBAAuB,KAAK,KAAK;AAAA,IACxC;AAEA,SAAQ,YAAY,CAAC,YAAqC;AACxD,YAAM,eAAe,KAAK,OAAO,QAAQ,MAAM;AAC/C,UAAI,CAAC,aAAc;AAEnB,YAAM,eAAe,aAAa,SAAS;AAE3C,UAAI,QAAQ,SAAS,QAAQ;AAC3B,aAAK,uBAAuB;AAG5B,YAAI,KAAK,kBAAkB,SAAS,GAAG;AACrC,eAAK,kBAAkB;AAAA,QACzB;AAAA,MACF,WAAW,QAAQ,SAAS,aAAa;AACvC,aAAK,4BAA4B;AAAA,MAEnC;AAAA,IACF;AA0DA,SAAQ,QAAQ,MAAM;AAEpB,UAAI,KAAK,kBAAkB,SAAS,GAAG;AACrC,aAAK,kBAAkB;AAAA,MACzB;AACA,UAAI,KAAK,uBAAuB,SAAS,GAAG;AAC1C,aAAK,uBAAuB;AAAA,MAC9B;AAEA,WAAK,IAAI,uBAAuB,KAAK,cAAc,MAAM,iBAAiB;AAC1E,WAAK,KAAK,YAAY,KAAK,aAAa;AAAA,IAC1C;AAtIE,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,iBAAiB;AAEvB,SAAK,OAAO,GAAG,aAAa,KAAK,WAAW;AAC5C,SAAK,OAAO,GAAG,kBAAkB,KAAK,gBAAgB;AACtD,SAAK,OAAO,GAAG,OAAO,KAAK,KAAK;AAGhC,UAAM,QAAQ,KAAK,OAAO,QAAQ;AAClC,QAAI,OAAO;AACT,YAAM,GAAG,WAAW,KAAK,SAAS;AAAA,IACpC;AAAA,EACF;AAAA,EAqDQ,oBAAoB;AAC1B,QAAI,KAAK,kBAAkB,WAAW,EAAG;AACzC,QAAI,KAAK,uBAAuB,EAAG;AAEnC,UAAM,eAAe,KAAK,OAAO,QAAQ,MAAM;AAC/C,QAAI,CAAC,aAAc;AAEnB,UAAM,UAAU,aAAa,KAAK,oBAAoB;AACtD,UAAM,SAAS,OAAO,OAAO,KAAK,iBAAiB;AAEnD,UAAM,eAA6B;AAAA,MACjC;AAAA,MACA,cAAc,KAAK;AAAA,MACnB,SAAS,aAAa,UAAU,QAAQ,UAAU;AAAA,MAClD,MAAM;AAAA,IACR;AAEA,SAAK;AAAA,MACH,yBAAyB,OAAO,MAAM,yBAAyB,KAAK,oBAAoB;AAAA,IAC1F;AACA,SAAK,cAAc,KAAK,YAAY;AACpC,SAAK,KAAK,gBAAgB,YAAY;AAGtC,SAAK,oBAAoB,CAAC;AAC1B,SAAK,uBAAuB;AAAA,EAC9B;AAAA,EAEQ,yBAAyB;AAC/B,QAAI,KAAK,uBAAuB,WAAW,EAAG;AAC9C,QAAI,KAAK,4BAA4B,EAAG;AAExC,UAAM,eAAe,KAAK,OAAO,QAAQ,MAAM;AAC/C,QAAI,CAAC,aAAc;AAEnB,UAAM,UAAU,aAAa,KAAK,yBAAyB;AAC3D,UAAM,SAAS,OAAO,OAAO,KAAK,sBAAsB;AAExD,UAAM,eAA6B;AAAA,MACjC;AAAA,MACA,cAAc,KAAK;AAAA,MACnB,SAAS,aAAa,UAAU,QAAQ,UAAU;AAAA,MAClD,MAAM;AAAA,IACR;AAEA,SAAK;AAAA,MACH,8BAA8B,OAAO,MAAM,yBAAyB,KAAK,yBAAyB;AAAA,IACpG;AACA,SAAK,cAAc,KAAK,YAAY;AACpC,SAAK,KAAK,gBAAgB,YAAY;AAGtC,SAAK,yBAAyB,CAAC;AAC/B,SAAK,4BAA4B;AAAA,EACnC;AAAA,EAeO,mBAAmC;AACxC,WAAO,CAAC,GAAG,KAAK,aAAa;AAAA,EAC/B;AAAA,EAEO,UAAU;AACf,SAAK,IAAI,WAAW;AACpB,SAAK,OAAO,IAAI,aAAa,KAAK,WAAW;AAC7C,SAAK,OAAO,IAAI,kBAAkB,KAAK,gBAAgB;AACvD,SAAK,OAAO,IAAI,OAAO,KAAK,KAAK;AAEjC,UAAM,QAAQ,KAAK,OAAO,QAAQ;AAClC,QAAI,OAAO;AACT,YAAM,IAAI,WAAW,KAAK,SAAS;AAAA,IACrC;AAEA,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEU,OAAO,SAAgB;AAC/B,SAAK,QAAQ,IAAI,GAAG,OAAO;AAAA,EAC7B;AACF;;;ACzLA,SAAS,gBAAAC,qBAAoB;AAStB,IAAe,MAAf,cAA2BA,cAAwB;AAAA,EAM9C,OAAO,SAAgB;AAC/B,SAAK,QAAQ,IAAI,GAAG,OAAO;AAAA,EAC7B;AAAA,EAEA,UAAU;AACR,SAAK,IAAI,WAAW;AACpB,SAAK,mBAAmB;AAAA,EAC1B;AACF;;;ACrBO,IAAM,UAAN,cAAsB,IAAI;AAAA,EAA1B;AAAA;AACL,SAAQ,IAAI;AAAA;AAAA,EAEZ,MAAM,aAAa;AACjB,eAAW,MAAM;AACf,WAAK,KAAK,cAAc,gBAAgB,KAAK,GAAG,EAAE;AAAA,IACpD,GAAG,GAAG;AAAA,EACR;AACF;;;ACVA,SAAS,eAAAC,oBAA6B;AAQ/B,IAAM,cAAN,cAA0B,IAAI;AAAA;AAAA,EAInC,YAA6B,SAA6B;AACxD,UAAM;AADqB;AAH7B,SAAQ,MAAkB;AAC1B,SAAQ,WAAW;AAuCnB,SAAQ,eAAe,CAAC,eAAuB;AAC7C,WAAK,KAAK,cAAc,UAAU;AAAA,IACpC;AAEA,SAAQ,WAAW,CAAC,WAAqB;AACvC,WAAK,IAAI,6BAA6B;AACtC,WAAK,aAAa;AAElB,UAAI,OAAO,SAAS,GAAG;AACrB,aAAK,IAAI,4BAA4B;AACrC,cAAM,SAAS,IAAIC,aAAY;AAC/B,aAAK,KAAK,WAAW,MAAM;AAC3B,eAAO,QAAQ,CAAC,UAAU,OAAO,MAAM,KAAK,CAAC;AAC7C,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAlDE,QAAI,KAAK,QAAQ,UAAU,WAAW,GAAG;AACvC,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,WAAW,aAAuB;AAChC,SAAK,KAAK,WAAW,WAAW;AAAA,EAClC;AAAA,EAEA,UAAU;AACR,UAAM,QAAQ;AACd,SAAK,KAAK,QAAQ;AAClB,SAAK,MAAM;AACX,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,eAAe;AACrB,SAAK;AACL,QAAI,KAAK,YAAY,KAAK,QAAQ,UAAU,QAAQ;AAClD,WAAK,WAAW;AAAA,IAClB;AACA,SAAK,KAAK,QAAQ;AAClB,SAAK,MAAM,KAAK,QAAQ,UAAU,KAAK,QAAQ,EAAE;AACjD,SAAK,IAAI,GAAG,cAAc,KAAK,YAAY;AAC3C,SAAK,IAAI,GAAG,UAAU,KAAK,QAAQ;AAGnC,eAAW,MAAM;AACf,UAAI,KAAK,OAAO,KAAK,QAAQ;AAC3B,aAAK,IAAI,SAAS,IAAI,OAAO,KAAK,IAAI,YAAY,IAAI;AAAA,MACxD;AAAA,IACF,GAAG,CAAC;AAAA,EACN;AAkBF;;;ACjEA,YAAY,QAAQ;AACpB,SAAS,eAAAC,oBAA6B;;;ACDtC,SAAS,gBAAAC,qBAAoB;AAStB,IAAe,MAAf,cAA2BA,cAAwB;AAAA,EAM9C,OAAO,SAAgB;AAC/B,SAAK,QAAQ,IAAI,GAAG,OAAO;AAAA,EAC7B;AAAA,EAEA,UAAU;AACR,SAAK,IAAI,WAAW;AACpB,SAAK,OAAO;AAAA,EACd;AACF;;;ADnBO,IAAM,UAAN,cAAsB,IAAI;AAAA,EAC/B,YAAoB,gBAA0B;AAC5C,UAAM;AADY;AAAA,EAEpB;AAAA,EAEA,MAAM,YAAsB;AAC1B,UAAM,cAAc,IAAIC,aAAY;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;;;AExBA,SAAS,eAAAC,oBAA6B;AAQ/B,IAAM,cAAN,cAA0B,IAAI;AAAA;AAAA,EAInC,YAA6B,SAA6B;AACxD,UAAM;AADqB;AAH7B,SAAQ,MAAkB;AAC1B,SAAQ,WAAW;AA2CnB,SAAQ,UAAU,CAAC,UAAkB;AACnC,WAAK,KAAK,SAAS,KAAK;AAAA,IAC1B;AAEA,SAAQ,WAAW,CAAC,WAAqB;AACvC,WAAK,IAAI,6BAA6B;AACtC,WAAK,aAAa;AAElB,UAAI,OAAO,SAAS,GAAG;AACrB,aAAK,IAAI,2BAA2B;AACpC,cAAM,SAAS,IAAIC,aAAY;AAC/B,aAAK,KAAK,MAAM,MAAM;AACtB,eAAO,QAAQ,CAAC,UAAU,OAAO,MAAM,KAAK,CAAC;AAC7C,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAtDE,QAAI,KAAK,QAAQ,UAAU,WAAW,GAAG;AACvC,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,MAAM,YAAsB;AAC1B,SAAK,KAAK,MAAM,UAAU;AAAA,EAC5B;AAAA,EAEA,SAAS;AACP,SAAK,KAAK,OAAO;AAAA,EACnB;AAAA,EAEA,UAAU;AACR,UAAM,QAAQ;AACd,SAAK,KAAK,QAAQ;AAClB,SAAK,MAAM;AACX,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,eAAe;AACrB,SAAK;AACL,QAAI,KAAK,YAAY,KAAK,QAAQ,UAAU,QAAQ;AAClD,WAAK,WAAW;AAAA,IAClB;AACA,SAAK,KAAK,QAAQ;AAClB,SAAK,MAAM,KAAK,QAAQ,UAAU,KAAK,QAAQ,EAAE;AACjD,SAAK,IAAI,GAAG,SAAS,KAAK,OAAO;AACjC,SAAK,IAAI,GAAG,UAAU,KAAK,QAAQ;AAGnC,eAAW,MAAM;AACf,UAAI,KAAK,OAAO,KAAK,QAAQ;AAC3B,aAAK,IAAI,SAAS,IAAI,OAAO,KAAK,IAAI,YAAY,IAAI;AAAA,MACxD;AAAA,IACF,GAAG,CAAC;AAAA,EACN;AAkBF;;;AClEA,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":["MicdropErrorCode","EventEmitter","PassThrough","MicdropClientCommands","MicdropServerCommands","EventEmitter","PassThrough","EventEmitter","EventEmitter","PassThrough","PassThrough","PassThrough","EventEmitter","PassThrough","PassThrough","PassThrough"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent/Agent.ts","../src/agent/tools.ts","../src/Logger.ts","../src/agent/FallbackAgent.ts","../src/agent/MockAgent.ts","../src/errors.ts","../src/MicdropServer.ts","../src/types.ts","../src/recorder/MicdropRecorder.ts","../src/stt/STT.ts","../src/stt/MockSTT.ts","../src/stt/FallbackSTT.ts","../src/tts/MockTTS.ts","../src/tts/TTS.ts","../src/tts/FallbackTTS.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 // Emitted when the agent gives up generating an answer (e.g. after exhausting\n // its retries). Used by FallbackAgent to switch to the next agent.\n Failed: []\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 public tools: Tool[]\n\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: (_input, agent) => agent.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: (_input, agent) => agent.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: (_input, agent) => agent.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, this) : {}\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'\nimport type { Agent } from './Agent'\n\nexport interface Tool<Schema extends z.ZodObject = z.ZodObject> {\n name: string\n description: string\n inputSchema?: Schema\n // The executing agent is passed as context so tools stay portable (no binding\n // to a specific agent instance), which lets them be shared between agents.\n execute?: (input: z.infer<Schema>, agent: Agent) => 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","export class Logger {\n constructor(public 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 { PassThrough } from 'stream'\nimport { Logger } from '../Logger'\nimport { MicdropConversationItem, MicdropToolCall } from '../types'\nimport { Agent } from './Agent'\n\nexport interface FallbackAgentOptions {\n factories: Array<() => Agent>\n}\n\nexport class FallbackAgent extends Agent {\n private agent: Agent | null = null\n private agentIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly fallbackOptions: FallbackAgentOptions) {\n super({ systemPrompt: '' })\n if (this.fallbackOptions.factories.length === 0) {\n throw new Error('FallbackAgent: No factories provided')\n }\n this.startNextAgent()\n }\n\n // Delegate extraction to the active agent (extract config lives on children)\n extract(message: string) {\n return this.agent ? this.agent.extract(message) : super.extract(message)\n }\n\n protected async generateAnswer(stream: PassThrough): Promise<void> {\n // Try each agent once (one full rotation) until one answers successfully.\n // The conversation is shared between agents, so the next agent picks up\n // exactly where the failed one stopped.\n for (\n let attempt = 0;\n attempt < this.fallbackOptions.factories.length;\n attempt++\n ) {\n const agent = this.agent\n if (!agent) return\n\n let failed = false\n const onFailed = () => {\n failed = true\n }\n agent.once('Failed', onFailed)\n\n try {\n await this.pipeAnswer(agent, stream)\n } finally {\n agent.off('Failed', onFailed)\n }\n\n if (!failed) return\n\n this.log('Agent failed, trying next agent')\n this.startNextAgent()\n }\n\n // Every agent failed within this rotation: report it so an outer consumer\n // (e.g. a wrapping FallbackAgent) can react.\n this.log('All agents failed')\n this.emit('Failed')\n }\n\n cancel() {\n this.agent?.cancel()\n }\n\n destroy() {\n super.destroy()\n this.agent?.destroy()\n this.agent = null\n this.agentIndex = -1\n }\n\n // Run the child agent and forward its answer chunks to our own stream\n private pipeAnswer(agent: Agent, stream: PassThrough): Promise<void> {\n return new Promise((resolve) => {\n const answerStream = agent.answer()\n answerStream.on('data', (chunk) => {\n if (stream.writable) {\n stream.write(chunk)\n }\n })\n answerStream.on('end', resolve)\n answerStream.on('error', resolve)\n })\n }\n\n private startNextAgent() {\n this.agentIndex++\n if (this.agentIndex >= this.fallbackOptions.factories.length) {\n this.agentIndex = 0\n }\n\n const previousAgent = this.agent\n const isFirstAgent = previousAgent === null\n const agent = this.fallbackOptions.factories[this.agentIndex]()\n this.agent = agent\n\n // Share the conversation and tools between the fallback and the child agent.\n // Both are now portable (tools no longer bind to a specific instance), so a\n // single reference is shared, exactly like the conversation.\n if (isFirstAgent) {\n // Adopt the first agent's conversation and tools (keeps its system prompt)\n this.conversation = agent.conversation\n this.tools = agent.tools\n } else {\n // Keep the accumulated history, but use the new agent's system prompt\n if (agent.conversation[0]?.role === 'system') {\n this.conversation[0] = agent.conversation[0]\n }\n agent.conversation = this.conversation\n agent.tools = this.tools\n }\n\n // Forward events from the child agent\n agent.on('Message', this.onMessage)\n agent.on('CancelLastUserMessage', this.onCancelLastUserMessage)\n agent.on('SkipAnswer', this.onSkipAnswer)\n agent.on('EndCall', this.onEndCall)\n agent.on('ToolCall', this.onToolCall)\n\n // Destroy the previous agent (after moving the conversation over)\n previousAgent?.destroy()\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.agent && this.logger) {\n this.agent.logger = new Logger(this.agent.constructor.name)\n }\n }, 0)\n }\n\n private onMessage = (message: MicdropConversationItem) => {\n this.emit('Message', message)\n }\n\n private onCancelLastUserMessage = () => {\n this.emit('CancelLastUserMessage')\n }\n\n private onSkipAnswer = () => {\n this.emit('SkipAnswer')\n }\n\n private onEndCall = () => {\n this.emit('EndCall')\n }\n\n private onToolCall = (toolCall: MicdropToolCall) => {\n this.emit('ToolCall', toolCall)\n }\n}\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 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","import { EventEmitter } from 'eventemitter3'\nimport { 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 MicdropServerEvents {\n End: [MicdropCallSummary]\n UserAudio: [Buffer]\n AssistantAudio: [Buffer]\n}\n\nexport interface MicdropConfig {\n firstMessage?: string\n generateFirstMessage?: boolean\n agent: Agent\n stt: STT\n tts: TTS\n}\n\nexport class MicdropServer extends EventEmitter<MicdropServerEvents> {\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 private userSpeechChunks = 0\n\n constructor(socket: WebSocket, config: MicdropConfig) {\n super()\n this.socket = socket\n this.config = config\n this.log(`Call started`)\n\n // Setup STT\n this.config.stt.on('Transcript', this.onTranscriptSTT)\n\n // Setup TTS\n this.config.tts.on('Audio', this.onAudioTTS)\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 // Deferred so consumers (e.g. MicdropRecorder) can subscribe to agent\n // events before the first message is added to the conversation.\n queueMicrotask(() => 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 // Emit End event\n this.emit('End', {\n conversation: this.config.agent.conversation,\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.onUserAudio(message)\n }\n }\n\n private onUserAudio(chunk: Buffer) {\n this.log(`Received chunk (${chunk.byteLength} bytes)`)\n this.currentUserStream?.write(chunk)\n this.userSpeechChunks++\n this.emit('UserAudio', chunk)\n }\n\n private onMute() {\n this.userSpeechChunks = 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.cancel()\n }\n\n private onStartSpeaking() {\n if (!this.config) return\n this.userSpeechChunks = 0\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 const hasNoUserSpeech =\n !this.currentUserStream || this.userSpeechChunks === 0\n this.currentUserStream?.end()\n this.currentUserStream = undefined\n this.userSpeechChunks = 0\n\n // If user is not speaking or no chunks were received, skip\n if (hasNoUserSpeech) {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\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 onTranscriptSTT = async (transcript: string) => {\n if (!this.config) return\n\n // Skip answer if transcript is empty\n if (transcript === '') {\n this.socket?.send(MicdropServerCommands.SkipAnswer)\n return\n }\n\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 onAudioTTS = (audio: Buffer) => {\n if (!this.socket) return\n this.log(`Send audio chunk (${audio.byteLength} bytes)`)\n this.socket.send(audio)\n this.emit('AssistantAudio', audio)\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 this.config.tts.speak(textStream)\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 type { MicdropServer } from '../MicdropServer'\nimport type { MicdropConversationItem } from '../types'\nimport { Logger } from '../Logger'\n\nexport interface AudioMessage {\n buffer: Buffer\n messageIndex: number\n message: string\n role: 'user' | 'assistant'\n}\n\nexport interface MicdropRecorderEvents {\n AudioMessage: [AudioMessage]\n Complete: [AudioMessage[]]\n}\n\nexport class MicdropRecorder extends EventEmitter<MicdropRecorderEvents> {\n public logger?: Logger\n\n private audioMessages: AudioMessage[] = []\n private currentUserChunks: Buffer[] = []\n private currentAssistantChunks: Buffer[] = []\n private lastUserMessageIndex: number = -1\n private lastAssistantMessageIndex: number = -1\n\n constructor(private server: MicdropServer) {\n super()\n this.setupListeners()\n }\n\n private setupListeners() {\n // Listen to audio events from server\n this.server.on('UserAudio', this.onUserAudio)\n this.server.on('AssistantAudio', this.onAssistantAudio)\n this.server.on('End', this.onEnd)\n\n // Listen to message events from agent\n const agent = this.server.config?.agent\n if (agent) {\n agent.on('Message', this.onMessage)\n }\n }\n\n private onUserAudio = (chunk: Buffer) => {\n // Finalize or discard assistant audio when user starts speaking\n if (this.currentAssistantChunks.length > 0) {\n if (this.lastAssistantMessageIndex >= 0) {\n this.finalizeAssistantAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned assistant audio chunks')\n this.currentAssistantChunks = []\n }\n }\n\n this.log('Recording user audio chunk')\n this.currentUserChunks.push(chunk)\n }\n\n private onAssistantAudio = (chunk: Buffer) => {\n // Finalize or discard user audio when assistant starts speaking\n if (this.currentUserChunks.length > 0) {\n if (this.lastUserMessageIndex >= 0) {\n this.finalizeUserAudio()\n } else {\n // Discard orphaned chunks (no associated message)\n this.log('Discarding orphaned user audio chunks')\n this.currentUserChunks = []\n }\n }\n\n this.log('Recording assistant audio chunk')\n this.currentAssistantChunks.push(chunk)\n }\n\n private onMessage = (message: MicdropConversationItem) => {\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const messageIndex = conversation.length - 1\n\n if (message.role === 'user') {\n this.lastUserMessageIndex = messageIndex\n // User audio might already be complete, finalize if we have chunks\n // Audio chunks arrive BEFORE message, so we finalize when we know the message\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n } else if (message.role === 'assistant') {\n this.lastAssistantMessageIndex = messageIndex\n // Don't finalize assistant audio here - chunks can still arrive after message\n }\n }\n\n private finalizeUserAudio() {\n if (this.currentUserChunks.length === 0) return\n if (this.lastUserMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastUserMessageIndex]\n const buffer = Buffer.concat(this.currentUserChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastUserMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'user',\n }\n\n this.log(\n `Finalized user audio: ${buffer.length} bytes, message index ${this.lastUserMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentUserChunks = []\n this.lastUserMessageIndex = -1\n }\n\n private finalizeAssistantAudio() {\n if (this.currentAssistantChunks.length === 0) return\n if (this.lastAssistantMessageIndex < 0) return\n\n const conversation = this.server.config?.agent.conversation\n if (!conversation) return\n\n const message = conversation[this.lastAssistantMessageIndex]\n const buffer = Buffer.concat(this.currentAssistantChunks)\n\n const audioMessage: AudioMessage = {\n buffer,\n messageIndex: this.lastAssistantMessageIndex,\n message: 'content' in message ? message.content : '',\n role: 'assistant',\n }\n\n this.log(\n `Finalized assistant audio: ${buffer.length} bytes, message index ${this.lastAssistantMessageIndex}`\n )\n this.audioMessages.push(audioMessage)\n this.emit('AudioMessage', audioMessage)\n\n // Reset\n this.currentAssistantChunks = []\n this.lastAssistantMessageIndex = -1\n }\n\n private onEnd = () => {\n // Finalize any remaining audio\n if (this.currentUserChunks.length > 0) {\n this.finalizeUserAudio()\n }\n if (this.currentAssistantChunks.length > 0) {\n this.finalizeAssistantAudio()\n }\n\n this.log(`Recording complete: ${this.audioMessages.length} audio messages`)\n this.emit('Complete', this.audioMessages)\n }\n\n public getAudioMessages(): AudioMessage[] {\n return [...this.audioMessages]\n }\n\n public destroy() {\n this.log('Destroyed')\n this.server.off('UserAudio', this.onUserAudio)\n this.server.off('AssistantAudio', this.onAssistantAudio)\n this.server.off('End', this.onEnd)\n\n const agent = this.server.config?.agent\n if (agent) {\n agent.off('Message', this.onMessage)\n }\n\n this.removeAllListeners()\n }\n\n protected log(...message: any[]) {\n this.logger?.log(...message)\n }\n}\n","import { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface STTEvents {\n Transcript: [string]\n Failed: [Buffer[]]\n}\n\nexport abstract class STT extends EventEmitter<STTEvents> {\n public logger?: Logger\n\n // Set stream of audio to transcribe\n abstract transcribe(audioStream: Readable): void\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","import { STT } from './STT'\n\nexport class MockSTT extends STT {\n private i = 0\n\n async transcribe() {\n setTimeout(() => {\n this.emit('Transcript', `User Message ${this.i++}`)\n }, 300)\n }\n}\n","import { PassThrough, Readable } from 'stream'\nimport { STT } from './STT'\nimport { Logger } from '..'\n\nexport interface FallbackSTTOptions {\n factories: Array<() => STT>\n}\n\nexport class FallbackSTT extends STT {\n private stt: STT | null = null\n private sttIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackSTTOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackSTT: No factories provided')\n }\n this.startNextSTT()\n }\n\n transcribe(audioStream: Readable) {\n this.stt?.transcribe(audioStream)\n }\n\n destroy() {\n super.destroy()\n this.stt?.destroy()\n this.stt = null\n this.sttIndex = -1\n }\n\n private startNextSTT() {\n this.sttIndex++\n if (this.sttIndex >= this.options.factories.length) {\n this.sttIndex = 0\n }\n this.stt?.destroy()\n this.stt = this.options.factories[this.sttIndex]()\n this.stt.on('Transcript', this.onTranscript)\n this.stt.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.stt && this.logger) {\n this.stt.logger = new Logger(this.stt.constructor.name)\n }\n }, 0)\n }\n\n private onTranscript = (transcript: string) => {\n this.emit('Transcript', transcript)\n }\n\n private onFailed = (chunks: Buffer[]) => {\n this.log('STT failed, trying next STT')\n this.startNextSTT()\n\n if (chunks.length > 0) {\n this.log('Sending audio chunks again')\n const stream = new PassThrough()\n this.stt?.transcribe(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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 { EventEmitter } from 'eventemitter3'\nimport { Readable } from 'stream'\nimport { Logger } from '../Logger'\n\nexport interface TTSEvents {\n Audio: [Buffer]\n Failed: [string[]]\n}\n\nexport abstract class TTS extends EventEmitter<TTSEvents> {\n public logger?: Logger\n\n abstract speak(textStream: Readable): void\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 { PassThrough, Readable } from 'stream'\nimport { TTS } from './TTS'\nimport { Logger } from '..'\n\nexport interface FallbackTTSOptions {\n factories: Array<() => TTS>\n}\n\nexport class FallbackTTS extends TTS {\n private tts: TTS | null = null\n private ttsIndex = -1 // Start at -1 because we need to increment it before using it\n\n constructor(private readonly options: FallbackTTSOptions) {\n super()\n if (this.options.factories.length === 0) {\n throw new Error('FallbackTTS: No factories provided')\n }\n this.startNextTTS()\n }\n\n speak(textStream: Readable) {\n this.tts?.speak(textStream)\n }\n\n cancel() {\n this.tts?.cancel()\n }\n\n destroy() {\n super.destroy()\n this.tts?.destroy()\n this.tts = null\n this.ttsIndex = -1\n }\n\n private startNextTTS() {\n this.ttsIndex++\n if (this.ttsIndex >= this.options.factories.length) {\n this.ttsIndex = 0\n }\n this.tts?.destroy()\n this.tts = this.options.factories[this.ttsIndex]()\n this.tts.on('Audio', this.onAudio)\n this.tts.on('Failed', this.onFailed)\n\n // Set logger after event loop\n setTimeout(() => {\n if (this.tts && this.logger) {\n this.tts.logger = new Logger(this.tts.constructor.name)\n }\n }, 0)\n }\n\n private onAudio = (audio: Buffer) => {\n this.emit('Audio', audio)\n }\n\n private onFailed = (chunks: string[]) => {\n this.log('TTS failed, trying next TTS')\n this.startNextTTS()\n\n if (chunks.length > 0) {\n this.log('Sending text chunks again')\n const stream = new PassThrough()\n this.tts?.speak(stream)\n chunks.forEach((chunk) => stream.write(chunk))\n stream.end()\n }\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":["MicdropErrorCode","EventEmitter","PassThrough","MicdropClientCommands","MicdropServerCommands","EventEmitter","PassThrough","EventEmitter","EventEmitter","PassThrough","PassThrough","PassThrough","EventEmitter","PassThrough","PassThrough","PassThrough"]}
|