@mastra/livekit 0.2.0-alpha.0 → 0.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,68 @@
1
+ import type { VoiceReplyGenerator, VoiceToolCall, VoiceTurnCompleteHook } from './bridge.js';
2
+ /** Connect + first-token budget when not overridden. Plugin mode passes `connOptions.timeoutMs`. */
3
+ export declare const DEFAULT_REMOTE_TIMEOUT_MS = 10000;
4
+ /** Standalone initial-connection retry attempts. Plugin mode forces this to 0 (base class owns retries). */
5
+ export declare const DEFAULT_REMOTE_RETRIES = 2;
6
+ /**
7
+ * Options for the remote Mastra transport. Shape mirrors the in-process `AgentReplyGeneratorOptions`
8
+ * so `MastraLLM` can accept either source interchangeably.
9
+ */
10
+ export interface RemoteMastraAgentOptions {
11
+ /** Base URL of the remote Mastra server, e.g. `https://my-app.mastra.cloud`. */
12
+ baseUrl: string;
13
+ /** Agent key in the Mastra config's `agents`. */
14
+ agentId: string;
15
+ /** Path prefix for the Mastra API. Defaults to `'/api'`. */
16
+ apiPrefix?: string;
17
+ /** Static headers, or a (possibly async) resolver invoked per turn — e.g. to mint a fresh token. */
18
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
19
+ /** Injectable `fetch` for tests/proxies. Defaults to `globalThis.fetch`. */
20
+ fetch?: typeof globalThis.fetch;
21
+ /**
22
+ * Connect + first-token timeout in ms. Plugin mode default: LiveKit's `connOptions.timeoutMs` (10s).
23
+ * Standalone default: {@link DEFAULT_REMOTE_TIMEOUT_MS}.
24
+ */
25
+ timeoutMs?: number;
26
+ /**
27
+ * Initial-connection retry attempts (before the first chunk only). Standalone default:
28
+ * {@link DEFAULT_REMOTE_RETRIES}. In plugin mode the LiveKit base class owns retries and this is
29
+ * forced to 0.
30
+ */
31
+ retries?: number;
32
+ /** Extra fields merged into each stream request body (advanced). */
33
+ body?: Record<string, unknown>;
34
+ }
35
+ /** {@link RemoteMastraAgentOptions} plus the per-turn observer hooks the generator threads through. */
36
+ export interface RemoteAgentReplyGeneratorOptions extends RemoteMastraAgentOptions {
37
+ /** Speak a short phrase while a tool runs. See {@link MastraVoiceAgentOptions.toolFeedback}. */
38
+ toolFeedback?: (toolCall: VoiceToolCall) => string | undefined | void;
39
+ /** Notified as each tool-call chunk arrives, mid-stream. See {@link MastraVoiceAgentOptions.onToolCall}. */
40
+ onToolCall?: (toolCall: VoiceToolCall) => void;
41
+ /** Fired off the audio path after the reply streams. See {@link MastraVoiceAgentOptions.onTurnComplete}. */
42
+ onTurnComplete?: VoiceTurnCompleteHook;
43
+ }
44
+ type RawChunk = {
45
+ type?: string;
46
+ payload?: Record<string, unknown>;
47
+ };
48
+ /**
49
+ * Reads a Mastra SSE stream and yields each event's parsed JSON. Framing matches the server's
50
+ * `processMastraStream` (buffer, split on `\n\n`, strip `data: `, stop on `[DONE]`); undecodable
51
+ * `data:` lines are skipped. Aborting `signal` cancels the underlying reader.
52
+ */
53
+ export declare function readMastraSSE(body: globalThis.ReadableStream<Uint8Array>, signal: AbortSignal): AsyncGenerator<RawChunk>;
54
+ /**
55
+ * A {@link VoiceReplyGenerator} that runs the Mastra agent loop on a **remote** Mastra server over
56
+ * HTTP/SSE. Shaped exactly like the in-process `createAgentReplyGenerator`: it consumes the same
57
+ * chunk vocabulary, drives the same `toolFeedback` / `onToolCall` / `onTurnComplete` seams, and
58
+ * cancelling the returned stream (LiveKit does this on barge-in) tears down the HTTP request so the
59
+ * server aborts generation.
60
+ *
61
+ * Usable standalone via the worker's `generate:` hatch (a minimum-viable remote worker mode), and as
62
+ * the transport `MastraLLM` wraps. Errors are thrown as LiveKit `APIError` subclasses so the plugin's
63
+ * base-class retry loop and `FallbackAdapter` behave; a connect + first-token watchdog prevents
64
+ * indefinite dead air.
65
+ */
66
+ export declare function createRemoteAgentReplyGenerator(options: RemoteAgentReplyGeneratorOptions): VoiceReplyGenerator;
67
+ export {};
68
+ //# sourceMappingURL=remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EAEb,qBAAqB,EAEtB,MAAM,UAAU,CAAC;AAGlB,oGAAoG;AACpG,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAChD,4GAA4G;AAC5G,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAQxC;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACpG,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,uGAAuG;AACvG,MAAM,WAAW,gCAAiC,SAAQ,wBAAwB;IAChF,gGAAgG;IAChG,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACtE,4GAA4G;IAC5G,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,4GAA4G;IAC5G,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAED,KAAK,QAAQ,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAwCrE;;;;GAIG;AACH,wBAAuB,aAAa,CAClC,IAAI,EAAE,UAAU,CAAC,cAAc,CAAC,UAAU,CAAC,EAC3C,MAAM,EAAE,WAAW,GAClB,cAAc,CAAC,QAAQ,CAAC,CAuC1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,gCAAgC,GAAG,mBAAmB,CA+N9G"}
@@ -1,203 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkMWTEZOBS_cjs = require('./chunk-MWTEZOBS.cjs');
4
+ var chunkDBVKNDAQ_cjs = require('./chunk-DBVKNDAQ.cjs');
4
5
  var agents = require('@livekit/agents');
5
6
  var requestContext = require('@mastra/core/request-context');
6
- var web = require('stream/web');
7
7
  var observability = require('@mastra/core/observability');
8
8
  var crypto = require('crypto');
9
9
  var url = require('url');
10
10
 
11
- // src/messages.ts
12
- function textOfMessage(message) {
13
- const parts = [];
14
- for (const part of message.content) {
15
- if (typeof part === "string") {
16
- parts.push(part);
17
- } else if (part.type === "instructions") {
18
- parts.push(part.value);
19
- } else if (part.type === "audio_content" && part.transcript) {
20
- parts.push(part.transcript);
21
- }
22
- }
23
- return parts.join("\n").trim();
24
- }
25
- function toVoiceTurnMessage(item) {
26
- if (item.type !== "message") return void 0;
27
- const content = textOfMessage(item);
28
- if (!content) return void 0;
29
- if (item.role === "user") return { role: "user", content };
30
- if (item.role === "assistant") return { role: "assistant", content };
31
- return { role: "system", content };
32
- }
33
- function extractNewTurnMessages(chatCtx) {
34
- const items = chatCtx.items;
35
- let lastAssistantIdx = -1;
36
- for (let i = items.length - 1; i >= 0; i--) {
37
- const item = items[i];
38
- if (item?.type === "message" && item.role === "assistant") {
39
- lastAssistantIdx = i;
40
- break;
41
- }
42
- }
43
- const messages = [];
44
- for (const item of items.slice(lastAssistantIdx + 1)) {
45
- const message = toVoiceTurnMessage(item);
46
- if (message) messages.push(message);
47
- }
48
- return messages;
49
- }
50
- function chatContextToMessages(chatCtx) {
51
- const withoutInstructions = chatCtx.copy({ excludeInstructions: true, excludeFunctionCall: true });
52
- const messages = [];
53
- for (const item of withoutInstructions.items) {
54
- const message = toVoiceTurnMessage(item);
55
- if (message) messages.push(message);
56
- }
57
- return messages;
58
- }
59
-
60
- // src/bridge.ts
61
- var DEFAULT_INSTRUCTIONS = "You are a helpful voice assistant powered by a Mastra agent.";
62
- function createAgentReplyGenerator(options) {
63
- const { agent, streamOptions, toolFeedback, onTurnComplete } = options;
64
- return (ctx) => {
65
- if (ctx.messages.length === 0) return null;
66
- const abortController = new AbortController();
67
- const mergedOptions = {
68
- ...streamOptions,
69
- abortSignal: abortController.signal
70
- };
71
- if (ctx.memory) mergedOptions.memory = ctx.memory;
72
- if (ctx.requestContext) mergedOptions.requestContext = ctx.requestContext;
73
- let cancelled = false;
74
- let replyText = "";
75
- const toolCalls = [];
76
- const emitTurnComplete = (interrupted) => {
77
- if (!onTurnComplete) return;
78
- const completeCtx = { ...ctx, result: { text: replyText, toolCalls, interrupted } };
79
- Promise.resolve().then(() => onTurnComplete(completeCtx)).catch((error) => {
80
- console.warn("@mastra/livekit: onTurnComplete hook threw", error);
81
- });
82
- };
83
- return new web.ReadableStream({
84
- start: async (controller) => {
85
- try {
86
- const result = await agent.stream(ctx.messages, mergedOptions);
87
- for await (const chunk of result.fullStream) {
88
- if (cancelled) break;
89
- if (chunk.type === "text-delta") {
90
- if (chunk.payload.text) {
91
- replyText += chunk.payload.text;
92
- controller.enqueue(chunk.payload.text);
93
- }
94
- } else if (chunk.type === "tool-call") {
95
- const toolCall = {
96
- toolCallId: chunk.payload.toolCallId,
97
- toolName: chunk.payload.toolName,
98
- args: chunk.payload.args
99
- };
100
- toolCalls.push(toolCall);
101
- if (toolFeedback) {
102
- const filler = toolFeedback(toolCall);
103
- if (filler) controller.enqueue(filler.endsWith(" ") ? filler : `${filler} `);
104
- }
105
- } else if (chunk.type === "error") {
106
- const error = chunk.payload.error;
107
- throw error instanceof Error ? error : new Error(String(error));
108
- }
109
- }
110
- if (!cancelled) controller.close();
111
- emitTurnComplete(cancelled);
112
- } catch (error) {
113
- if (cancelled || abortController.signal.aborted) {
114
- emitTurnComplete(true);
115
- return;
116
- }
117
- controller.error(error);
118
- }
119
- },
120
- cancel: () => {
121
- cancelled = true;
122
- abortController.abort();
123
- }
124
- });
125
- };
126
- }
127
- function toRequestContext(value) {
128
- if (!value) return void 0;
129
- if (value instanceof requestContext.RequestContext) return value;
130
- return new requestContext.RequestContext(Object.entries(value));
131
- }
132
- var MastraPlaceholderLLM = class extends agents.llm.LLM {
133
- label() {
134
- return "mastra.MastraVoiceAgent";
135
- }
136
- get model() {
137
- return "mastra-agent";
138
- }
139
- get provider() {
140
- return "mastra";
141
- }
142
- chat() {
143
- throw new Error(
144
- "@mastra/livekit: reply generation runs through the Mastra agent via llmNode; the placeholder LLM cannot be used for inference."
145
- );
146
- }
147
- };
148
- var MastraVoiceAgent = class extends agents.voice.Agent {
149
- mastraAgent;
150
- memory;
151
- requestContext;
152
- streamOptions;
153
- replyGenerator;
154
- constructor(options) {
155
- if (options.agent && options.generate) {
156
- throw new Error(
157
- "@mastra/livekit: MastraVoiceAgent requires `agent` or `generate`, not both \u2014 they are mutually exclusive reply sources."
158
- );
159
- }
160
- super({
161
- id: options.id,
162
- instructions: options.instructions ?? DEFAULT_INSTRUCTIONS,
163
- stt: options.stt,
164
- vad: options.vad,
165
- llm: new MastraPlaceholderLLM(),
166
- tts: options.tts,
167
- turnHandling: options.turnHandling
168
- });
169
- this.memory = options.memory ?? false;
170
- this.requestContext = toRequestContext(options.requestContext);
171
- this.streamOptions = options.streamOptions;
172
- if (options.generate) {
173
- this.replyGenerator = options.generate;
174
- } else if (options.agent) {
175
- this.mastraAgent = options.agent;
176
- this.replyGenerator = createAgentReplyGenerator({
177
- agent: options.agent,
178
- streamOptions: options.streamOptions,
179
- toolFeedback: options.toolFeedback,
180
- onTurnComplete: options.onTurnComplete
181
- });
182
- } else {
183
- throw new Error("@mastra/livekit: MastraVoiceAgent requires `agent` or `generate`.");
184
- }
185
- }
186
- async llmNode(chatCtx, _toolCtx, _modelSettings) {
187
- const messages = this.memory === false ? chatContextToMessages(chatCtx) : extractNewTurnMessages(chatCtx);
188
- if (messages.length === 0) return null;
189
- return this.replyGenerator({
190
- messages,
191
- chatCtx,
192
- memory: this.memory,
193
- requestContext: this.requestContext,
194
- tracingContext: this.streamOptions?.tracingContext
195
- });
196
- }
197
- };
198
- function createMastraVoiceAgent(options) {
199
- return new MastraVoiceAgent(options);
200
- }
201
11
  function modelMeta(metadata) {
202
12
  const out = {};
203
13
  if (metadata?.modelProvider) out.modelProvider = metadata.modelProvider;
@@ -473,6 +283,103 @@ async function resolveInstructions(mastraAgent, requestContext) {
473
283
  return void 0;
474
284
  }
475
285
  }
286
+ function resolveGreetingConfig(options) {
287
+ return {
288
+ text: options.greeting,
289
+ persist: options.persistGreeting,
290
+ ...options.configuration?.greeting
291
+ };
292
+ }
293
+ async function resolveGreetingText(text, context) {
294
+ const resolved = typeof text === "function" ? await text(context) : text;
295
+ return resolved || void 0;
296
+ }
297
+ async function resolveSessionComponent(resolver, fallback, context) {
298
+ const resolved = resolver ? await resolver(context) : void 0;
299
+ return resolved ?? fallback;
300
+ }
301
+ async function speakGreeting(session, greeting) {
302
+ if (!greeting.text) return void 0;
303
+ const handle = session.say(
304
+ greeting.text,
305
+ greeting.allowInterruptions === void 0 ? void 0 : { allowInterruptions: greeting.allowInterruptions }
306
+ );
307
+ if (greeting.awaitPlayout) {
308
+ await handle.waitForPlayout().catch(() => {
309
+ });
310
+ }
311
+ return handle;
312
+ }
313
+ var DEFAULT_END_CALL_TOOL = "endCall";
314
+ var DEFAULT_END_CALL_REASON = "agent ended call";
315
+ var DEFAULT_END_CALL_MAX_WAIT_MS = 3e4;
316
+ var DEFAULT_END_CALL_DRAIN_MS = 800;
317
+ var AGENT_BUSY_STATES = /* @__PURE__ */ new Set(["thinking", "speaking"]);
318
+ function waitForAgentDoneSpeaking(session, maxWaitMs = DEFAULT_END_CALL_MAX_WAIT_MS) {
319
+ if (!AGENT_BUSY_STATES.has(session.agentState)) return Promise.resolve();
320
+ return new Promise((resolve) => {
321
+ let timer;
322
+ const onChange = (ev) => {
323
+ if (AGENT_BUSY_STATES.has(ev.newState)) return;
324
+ cleanup();
325
+ resolve();
326
+ };
327
+ const cleanup = () => {
328
+ session.off(agents.voice.AgentSessionEventTypes.AgentStateChanged, onChange);
329
+ if (timer) clearTimeout(timer);
330
+ };
331
+ session.on(agents.voice.AgentSessionEventTypes.AgentStateChanged, onChange);
332
+ timer = setTimeout(() => {
333
+ cleanup();
334
+ resolve();
335
+ }, maxWaitMs);
336
+ timer.unref?.();
337
+ });
338
+ }
339
+ async function runEndCall(session, ctx, config, logger) {
340
+ try {
341
+ await waitForAgentDoneSpeaking(session, config.maxWaitMs ?? DEFAULT_END_CALL_MAX_WAIT_MS);
342
+ if (config.message) {
343
+ await session.say(config.message, { allowInterruptions: false }).waitForPlayout().catch(() => {
344
+ });
345
+ }
346
+ const drainMs = config.drainMs ?? DEFAULT_END_CALL_DRAIN_MS;
347
+ if (drainMs > 0) await new Promise((resolve) => setTimeout(resolve, drainMs));
348
+ } catch (error) {
349
+ logger.warn("@mastra/livekit: waiting for the agent to finish before ending the call failed", error);
350
+ } finally {
351
+ try {
352
+ await ctx.deleteRoom();
353
+ } catch (error) {
354
+ logger.warn("@mastra/livekit: deleteRoom while ending the call failed", error);
355
+ }
356
+ try {
357
+ ctx.shutdown(config.reason ?? DEFAULT_END_CALL_REASON);
358
+ } catch (error) {
359
+ logger.warn("@mastra/livekit: shutdown while ending the call failed", error);
360
+ }
361
+ }
362
+ }
363
+ function buildEndCallDetector(config, getSession, ctx, logger) {
364
+ if (!config) return void 0;
365
+ const toolName = config.tool ?? DEFAULT_END_CALL_TOOL;
366
+ let triggered = false;
367
+ return (turnCtx) => {
368
+ if (triggered) return;
369
+ if (!turnCtx.result.toolCalls.some((call) => call.toolName === toolName)) return;
370
+ const session = getSession();
371
+ if (!session) return;
372
+ triggered = true;
373
+ void runEndCall(session, ctx, config, logger);
374
+ };
375
+ }
376
+ function composeTurnComplete(user, detector) {
377
+ if (!detector) return user;
378
+ return (ctx) => {
379
+ void detector(ctx);
380
+ return user?.(ctx);
381
+ };
382
+ }
476
383
  function createLiveKitWorker(options) {
477
384
  if (options.generate && (options.agent || options.workflow)) {
478
385
  throw new Error(
@@ -489,6 +396,11 @@ function createLiveKitWorker(options) {
489
396
  "@mastra/livekit: `workflowInput` is required when `workflow` is set. Map the turn into the workflow inputData, e.g. workflowInput: ({ chatCtx }) => ({ history: chatContextToMessages(chatCtx) })."
490
397
  );
491
398
  }
399
+ if (options.generate && options.configuration?.endCall) {
400
+ throw new Error(
401
+ "@mastra/livekit: `configuration.endCall` has no effect with `generate` \u2014 the worker cannot observe tool calls from a custom reply generator. Detect the end-call tool inside your generator and call `runEndCall` directly instead."
402
+ );
403
+ }
492
404
  const wantsSileroVad = options.vad === void 0 || options.vad === "silero";
493
405
  if (options.turnDetection === "multilingual" || options.turnDetection === "english") {
494
406
  requestEouMethod(EOU_METHODS[options.turnDetection]);
@@ -514,6 +426,8 @@ function createLiveKitWorker(options) {
514
426
  const metadata = chunkMWTEZOBS_cjs.parseSessionMetadata(ctx.job.metadata);
515
427
  const args = { metadata, ctx };
516
428
  const requestContext$1 = metadata.requestContext ? new requestContext.RequestContext(Object.entries(metadata.requestContext)) : void 0;
429
+ const endCallDetector = buildEndCallDetector(options.configuration?.endCall, () => session, ctx, logger);
430
+ const onTurnComplete = composeTurnComplete(options.onTurnComplete, endCallDetector);
517
431
  let mastraAgent;
518
432
  let replyGenerator;
519
433
  let agentLabel;
@@ -530,7 +444,7 @@ function createLiveKitWorker(options) {
530
444
  replyStep: options.replyStep,
531
445
  resultText: options.resultText,
532
446
  toolFeedback: options.toolFeedback,
533
- onTurnComplete: options.onTurnComplete
447
+ onTurnComplete
534
448
  });
535
449
  } else {
536
450
  mastraAgent = await resolveMastraAgent(options, args);
@@ -580,24 +494,40 @@ function createLiveKitWorker(options) {
580
494
  const onCallEnd = options.onCallEnd;
581
495
  ctx.addShutdownCallback(async () => {
582
496
  try {
583
- await onCallEnd({ memory, memoryInstance, metadata, requestContext: requestContext$1, roomName, ctx });
497
+ await onCallEnd({
498
+ memory,
499
+ memoryInstance,
500
+ metadata,
501
+ requestContext: requestContext$1,
502
+ configuration: options.configuration,
503
+ roomName,
504
+ ctx
505
+ });
584
506
  } catch (error) {
585
507
  logger.warn("@mastra/livekit: onCallEnd hook threw", error);
586
508
  }
587
509
  });
588
510
  }
589
- const agent = createMastraVoiceAgent({
511
+ const greetingConfig = resolveGreetingConfig(options);
512
+ const greetingReminder = greetingConfig.repeatEvery && greetingConfig.repeatEvery > 0 ? { everyMs: greetingConfig.repeatEvery, text: greetingConfig.repeatText } : void 0;
513
+ const agent = chunkDBVKNDAQ_cjs.createMastraVoiceAgent({
590
514
  ...replyGenerator ? { generate: replyGenerator } : { agent: mastraAgent },
591
515
  instructions: mastraAgent ? await resolveInstructions(mastraAgent, requestContext$1) : void 0,
592
516
  memory,
593
517
  requestContext: requestContext$1,
594
518
  toolFeedback: options.toolFeedback,
595
- onTurnComplete: options.onTurnComplete,
519
+ onTurnComplete,
520
+ greetingReminder,
596
521
  streamOptions: voiceObs ? { tracingContext: voiceObs.tracingContext } : void 0
597
522
  });
523
+ const callContext = { metadata, requestContext: requestContext$1, roomName, ctx };
524
+ const [stt, tts] = await Promise.all([
525
+ resolveSessionComponent(options.configuration?.stt, options.stt, callContext),
526
+ resolveSessionComponent(options.configuration?.tts, options.tts, callContext)
527
+ ]);
598
528
  const session = new agents.voice.AgentSession({
599
- stt: options.stt,
600
- tts: options.tts,
529
+ stt,
530
+ tts,
601
531
  vad,
602
532
  turnHandling: buildTurnHandling(options, turnDetection),
603
533
  ...options.sessionOptions
@@ -610,18 +540,21 @@ function createLiveKitWorker(options) {
610
540
  inputOptions: options.inputOptions,
611
541
  outputOptions: options.outputOptions
612
542
  });
613
- if (options.greeting) {
614
- session.say(options.greeting);
615
- if (options.persistGreeting !== false && memory && memoryInstance) {
616
- try {
617
- await persistSpokenGreeting({
618
- memory: memoryInstance,
619
- threadId: memory.thread,
620
- resourceId: memory.resource ?? memory.thread,
621
- greeting: options.greeting
622
- });
623
- } catch (error) {
624
- logger.warn("@mastra/livekit: failed to persist the greeting", error);
543
+ if (greetingConfig.text) {
544
+ const greetingText = await resolveGreetingText(greetingConfig.text, callContext);
545
+ if (greetingText) {
546
+ await speakGreeting(session, { ...greetingConfig, text: greetingText });
547
+ if (greetingConfig.persist !== false && memory && memoryInstance) {
548
+ try {
549
+ await persistSpokenGreeting({
550
+ memory: memoryInstance,
551
+ threadId: memory.thread,
552
+ resourceId: memory.resource ?? memory.thread,
553
+ greeting: greetingText
554
+ });
555
+ } catch (error) {
556
+ logger.warn("@mastra/livekit: failed to persist the greeting", error);
557
+ }
625
558
  }
626
559
  }
627
560
  }
@@ -649,8 +582,22 @@ function runLiveKitWorker(options) {
649
582
  });
650
583
  }
651
584
 
652
- exports.chatContextToMessages = chatContextToMessages;
585
+ Object.defineProperty(exports, "chatContextToMessages", {
586
+ enumerable: true,
587
+ get: function () { return chunkDBVKNDAQ_cjs.chatContextToMessages; }
588
+ });
589
+ Object.defineProperty(exports, "createRemoteAgentReplyGenerator", {
590
+ enumerable: true,
591
+ get: function () { return chunkDBVKNDAQ_cjs.createRemoteAgentReplyGenerator; }
592
+ });
593
+ exports.DEFAULT_END_CALL_DRAIN_MS = DEFAULT_END_CALL_DRAIN_MS;
594
+ exports.DEFAULT_END_CALL_MAX_WAIT_MS = DEFAULT_END_CALL_MAX_WAIT_MS;
595
+ exports.DEFAULT_END_CALL_REASON = DEFAULT_END_CALL_REASON;
596
+ exports.DEFAULT_END_CALL_TOOL = DEFAULT_END_CALL_TOOL;
653
597
  exports.createLiveKitWorker = createLiveKitWorker;
598
+ exports.runEndCall = runEndCall;
654
599
  exports.runLiveKitWorker = runLiveKitWorker;
600
+ exports.speakGreeting = speakGreeting;
601
+ exports.waitForAgentDoneSpeaking = waitForAgentDoneSpeaking;
655
602
  //# sourceMappingURL=worker-entry.cjs.map
656
603
  //# sourceMappingURL=worker-entry.cjs.map