import { llm } from '@livekit/agents'; import type { APIConnectOptions } from '@livekit/agents'; import type { Agent as MastraAgent } from '@mastra/core/agent'; import { RequestContext } from '@mastra/core/request-context'; import type { MastraVoiceAgentMemory, VoiceReplyGenerator, VoiceToolCall, VoiceTurnCompleteHook } from './bridge.js'; import type { RemoteMastraAgentOptions } from './remote.js'; import type { VoiceTurnMetricsHook } from './turn-metrics.js'; export type { RemoteMastraAgentOptions } from './remote.js'; /** * Options for {@link MastraLLM}. Provide **exactly one** reply source — `remote` (the headline: a * Mastra app on a remote server), `agent` (an in-process Mastra agent), or `generate` (a custom * {@link VoiceReplyGenerator}). The `toolFeedback` / `onToolCall` / `onTurnComplete` hooks apply to * the `remote` and `agent` sources; a `generate` source owns its own hooks. */ export interface MastraLLMOptions { /** Per-attempt metrics; use observeVoiceSession for playback metrics. */ onTurnMetrics?: VoiceTurnMetricsHook; /** Remote Mastra server. Provide exactly one of `remote`, `agent`, `generate`. */ remote?: RemoteMastraAgentOptions; /** In-process Mastra agent (reuses `createAgentReplyGenerator`). */ agent?: MastraAgent; /** Custom reply source (escape hatch; owns its own tool-feedback / turn-complete behavior). */ generate?: VoiceReplyGenerator; /** * Conversation persistence, resolved by the customer per call (from SIP/caller identity). When set, * only messages new since the agent last spoke are sent each turn and Mastra Memory supplies * history. When omitted/false, the full LiveKit chat context is sent every turn. * * NOTE: incompatible with the session's `preemptiveGeneration` option — a speculative turn * persists a partial user message and a partial reply before being discarded. Leave preemptive * generation off when using `memory`, or set `memory.options.readOnly` and persist committed * turns yourself from the session's conversation-item events. * * The plugin cannot detect the combination at runtime, so this stays a documented constraint * rather than a warning: the LLM interface never receives the session (so the option can't be * read), a preemptive `chat()` is shape-identical to a real turn (LiveKit drives the same * `generateReply` with a draft transcript and no marker), and the observable signature — a * cancelled stream followed by a `chat()` whose trailing user message changed — is exactly what * an ordinary barge-in correction looks like, so a heuristic would warn on every barge-in. */ memory?: MastraVoiceAgentMemory | false; /** Request context forwarded to generation (tenant, dialed number, ...). */ requestContext?: RequestContext | Record; /** Speak a short filler while a (server-side) tool runs. Applies to the `remote`/`agent` sources. */ toolFeedback?: (toolCall: VoiceToolCall) => string | undefined | void; /** Notified as each tool-call chunk arrives, mid-stream. Applies to the `remote`/`agent` sources. */ onToolCall?: (toolCall: VoiceToolCall) => void; /** Fired off the audio path after each reply finishes. Applies to the `remote`/`agent` sources. */ onTurnComplete?: VoiceTurnCompleteHook; } /** * A standard LiveKit LLM plugin (`llm.LLM`) backed by a Mastra agent. Drop it into the `llm` slot of a * customer-owned `voice.AgentSession` and the Mastra app (agent loop, tools, memory, observability) * runs wherever it's deployed — most importantly on a **remote** Mastra server reached over HTTP. * * Tools are defined and executed **server-side** on the Mastra agent; LiveKit-side `toolCtx` is * ignored (with a one-time warning). Tool activity surfaces via `toolFeedback` (spoken) and * `onToolCall` / `onTurnComplete` (programmatic). `voice.Agent` instructions do **not** reach the * Mastra agent — put instructions on the Mastra agent instead. * * @example * ```ts * const session = new voice.AgentSession({ * stt: 'deepgram/nova-3', * tts: 'cartesia/sonic-3', * llm: new MastraLLM({ * remote: { baseUrl: process.env.MASTRA_URL!, agentId: 'callCenter' }, * memory: { thread: callId, resource: callerId }, * }), * }); * ``` */ export declare class MastraLLM extends llm.LLM { #private; constructor(options: MastraLLMOptions); label(): string; get model(): string; get provider(): string; /** * Resolves the reply generator for a turn. Non-remote sources are built once; the remote transport * is built per turn so its connect + first-token timeout can come from the session's * `connOptions.timeoutMs`, with base-class retries owning retry (transport `retries: 0`). */ private resolveGenerator; chat({ chatCtx, toolCtx, connOptions, }: { chatCtx: llm.ChatContext; toolCtx?: llm.ToolContext; connOptions?: APIConnectOptions; parallelToolCalls?: boolean; toolChoice?: llm.ToolChoice; extraKwargs?: Record; }): llm.LLMStream; /** No-op in v1: nothing in the LiveKit session/worker ever calls `prewarm()` automatically. */ prewarm(): void; } interface MastraLLMStreamOptions { onTurnMetrics?: VoiceTurnMetricsHook; chatCtx: llm.ChatContext; toolCtx?: llm.ToolContext; connOptions: APIConnectOptions; generator: VoiceReplyGenerator; memory: MastraVoiceAgentMemory | false; requestContext?: RequestContext; } /** * The `llm.LLMStream` `MastraLLM` returns per turn. `run()` extracts the turn's messages, drives * the reply generator, and pushes assistant `ChatChunk`s into `this.queue` (NOT `this.output` — the * base class drains queue → output and computes TTFT / duration / usage). Barge-in aborts via * `this.abortController` and `run()` returns silently. */ declare class MastraLLMStream extends llm.LLMStream { #private; constructor(mastraLLM: MastraLLM, options: MastraLLMStreamOptions); protected run(): Promise; } export { MastraLLMStream }; //# sourceMappingURL=llm-plugin.d.ts.map