From 11cb9486ecd4abcb7483174af3b35d365203077a Mon Sep 17 00:00:00 2001 From: Brian Yin Date: Mon, 13 Apr 2026 10:17:43 -0700 Subject: [PATCH 1/4] remove // Ref: --- plugins/assemblyai/src/stt.ts | 39 ----------------------------------- pnpm-lock.yaml | 26 +++++++++++------------ 2 files changed, 13 insertions(+), 52 deletions(-) diff --git a/plugins/assemblyai/src/stt.ts b/plugins/assemblyai/src/stt.ts index 76fa46c63..aa337934e 100644 --- a/plugins/assemblyai/src/stt.ts +++ b/plugins/assemblyai/src/stt.ts @@ -2,9 +2,6 @@ // // SPDX-License-Identifier: Apache-2.0 // -// Ported from: -// livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py -// See `// Ref: python ... - N-M lines` comments throughout for cross-references. import { type APIConnectOptions, type AudioBuffer, @@ -42,7 +39,6 @@ interface StreamEventMessage { session_duration_seconds?: number; } -// Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 46-66 lines export interface STTOptions { apiKey?: string; sampleRate: number; @@ -79,7 +75,6 @@ export interface STTOptions { baseUrl: string; } -// Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 72-97 lines const defaultSTTOptions: STTOptions = { apiKey: process.env.ASSEMBLYAI_API_KEY, sampleRate: 16000, @@ -89,7 +84,6 @@ const defaultSTTOptions: STTOptions = { baseUrl: 'wss://streaming.assemblyai.com', }; -// Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 72 lines export class STT extends stt.STT { #opts: STTOptions; label = 'assemblyai.STT'; @@ -103,25 +97,21 @@ export class STT extends stt.STT { } constructor(opts: Partial = {}) { - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 111-119 lines super({ streaming: true, interimResults: true, alignedTranscript: 'word', }); - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 120-122 lines if (opts.speechModel === 'u3-pro') { log().warn("'u3-pro' is deprecated, use 'u3-rt-pro' instead."); opts.speechModel = 'u3-rt-pro'; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 124-125 lines if (opts.prompt !== undefined && opts.speechModel !== 'u3-rt-pro') { throw new Error("The 'prompt' parameter is only supported with the 'u3-rt-pro' model."); } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 127-135 lines const apiKey = opts.apiKey ?? defaultSTTOptions.apiKey; if (!apiKey) { throw new Error( @@ -129,7 +119,6 @@ export class STT extends stt.STT { ); } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 147-149 lines // Minimize latency; matches LK's end-of-turn detector well. const minTurnSilence = opts.minTurnSilence ?? 100; @@ -143,24 +132,19 @@ export class STT extends stt.STT { // eslint-disable-next-line @typescript-eslint/no-unused-vars async _recognize(_: AudioBuffer): Promise { - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 185-192 lines throw new Error('Non-streaming recognize is not supported on AssemblyAI STT'); } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 212-257 lines updateOptions(opts: Partial) { this.#opts = { ...this.#opts, ...opts }; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 194-210 lines stream(options?: { connOptions?: APIConnectOptions }): SpeechStream { return new SpeechStream(this, this.#opts, options?.connOptions); } } -// Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 260 lines export class SpeechStream extends stt.SpeechStream { - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 262 lines static readonly CLOSE_MSG = JSON.stringify({ type: 'Terminate' }); #opts: STTOptions; @@ -184,7 +168,6 @@ export class SpeechStream extends stt.SpeechStream { * (before any speech events). Null until the connection completes. * Share this with the AssemblyAI team when reporting issues. */ - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 286-291 lines get sessionId(): string | null { return this.#sessionId; } @@ -193,12 +176,10 @@ export class SpeechStream extends stt.SpeechStream { * Unix timestamp when the AssemblyAI session expires. Set alongside * {@link sessionId} when the WebSocket connection is established. */ - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 293-297 lines get expiresAt(): number | null { return this.#expiresAt; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 299-351 lines updateOptions(opts: Partial) { this.#opts = { ...this.#opts, ...opts }; @@ -222,7 +203,6 @@ export class SpeechStream extends stt.SpeechStream { /** * Force-finalize the current turn immediately. */ - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 353-355 lines forceEndpoint() { this.#pendingConfigMessages.push({ type: 'ForceEndpoint' }); if (!this.#configMessagePending.done) this.#configMessagePending.resolve(); @@ -262,9 +242,7 @@ export class SpeechStream extends stt.SpeechStream { this.closed = true; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 442-505 lines async #connectWS(): Promise { - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 443-461 lines // u3-rt-pro has different silence defaults — if unset, both min and max default to 100ms. let minSilence = this.#opts.minTurnSilence; let maxSilence = this.#opts.maxTurnSilence; @@ -273,13 +251,11 @@ export class SpeechStream extends stt.SpeechStream { if (maxSilence === undefined) maxSilence = minSilence; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 476-480 lines // Default language_detection to true for multilingual / u3-rt-pro models, false otherwise. const defaultLanguageDetection = this.#opts.speechModel.includes('multilingual') || this.#opts.speechModel === 'u3-rt-pro'; const languageDetection = this.#opts.languageDetection ?? defaultLanguageDetection; - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 463-502 lines const liveConfig: Record = { sample_rate: this.#opts.sampleRate, encoding: this.#opts.encoding, @@ -301,7 +277,6 @@ export class SpeechStream extends stt.SpeechStream { }; const url = new URL(`${this.#opts.baseUrl}/v3/ws`); - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 498-502 lines // Python serializes booleans as the strings "true"/"false", so we mirror that. for (const [key, value] of Object.entries(liveConfig)) { if (value === undefined || value === null) continue; @@ -312,7 +287,6 @@ export class SpeechStream extends stt.SpeechStream { } } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 492-496 lines const ws = new WebSocket(url, { headers: { Authorization: this.#opts.apiKey!, @@ -330,7 +304,6 @@ export class SpeechStream extends stt.SpeechStream { return ws; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 357-440 lines async #runWS(ws: WebSocket) { let closing = false; const sessionController = new AbortController(); @@ -349,7 +322,6 @@ export class SpeechStream extends stt.SpeechStream { await Promise.race([closed, waitForAbort(controller.signal)]); }); - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 361-385 lines const sendTask = async () => { const samplesPerBuffer = Math.floor((this.#opts.sampleRate * this.#opts.bufferSizeMs) / 1000); const audioStream = new AudioByteStream(this.#opts.sampleRate, 1, samplesPerBuffer); @@ -393,7 +365,6 @@ export class SpeechStream extends stt.SpeechStream { } }; - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 387-418 lines let messageHandler: ((msg: RawData, isBinary: boolean) => void) | null = null; const listenTask = Task.from(async (controller) => { const listenMessage = new Promise((resolve, reject) => { @@ -419,7 +390,6 @@ export class SpeechStream extends stt.SpeechStream { await Promise.race([listenMessage, waitForAbort(controller.signal)]); }); - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 420-424 lines const configTask = Task.from(async (controller) => { // Drain any messages queued while the socket was reconnecting. while (this.#pendingConfigMessages.length > 0) { @@ -460,11 +430,9 @@ export class SpeechStream extends stt.SpeechStream { return words.reduce((sum, w) => sum + (w.confidence ?? 0), 0) / words.length; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 507-661 lines #processStreamEvent(data: StreamEventMessage) { const messageType = data.type; - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 510-518 lines if (messageType === 'Begin') { this.#sessionId = data.id ?? null; this.#expiresAt = data.expires_at ?? null; @@ -474,13 +442,11 @@ export class SpeechStream extends stt.SpeechStream { return; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 520-522 lines if (messageType === 'SpeechStarted') { this.queue.put({ type: stt.SpeechEventType.START_OF_SPEECH }); return; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 524-532 lines if (messageType === 'Termination') { this.#logger.debug( `AssemblyAI session terminated audio_duration=${data.audio_duration_seconds}s session_duration=${data.session_duration_seconds}s`, @@ -492,7 +458,6 @@ export class SpeechStream extends stt.SpeechStream { return; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 536-546 lines const words = data.words ?? []; const endOfTurn = Boolean(data.end_of_turn); const turnIsFormatted = Boolean(data.turn_is_formatted); @@ -500,7 +465,6 @@ export class SpeechStream extends stt.SpeechStream { const transcript = data.transcript ?? ''; const language = normalizeLanguage(data.language_code ?? 'en'); - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 555-564 lines // Word timestamps are in milliseconds: // https://www.assemblyai.com/docs/api-reference/streaming-api/streaming-api#receive.receiveTurn.words const timedWords = words.map((word) => @@ -517,7 +481,6 @@ export class SpeechStream extends stt.SpeechStream { let endTime = 0; let confidence = 0; - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 566-588 lines // `words` are cumulative for the turn — emit as an interim transcript. if (timedWords.length > 0) { const interimText = timedWords.map((w) => w.text).join(' '); @@ -540,7 +503,6 @@ export class SpeechStream extends stt.SpeechStream { }); } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 590-621 lines // `utterance` is chunk-based (not cumulative) — emit as a preflight transcript // covering only the words since the last preflight. if (utterance) { @@ -569,7 +531,6 @@ export class SpeechStream extends stt.SpeechStream { this.#lastPreflightStartTime = endTime; } - // Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 623-661 lines // End-of-turn: emit FINAL_TRANSCRIPT + END_OF_SPEECH. // If the user asked for formatted turns, wait for a formatted final. const waitingForFormatted = this.#opts.formatTurns === true && !turnIsFormatted; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e777f57ce..6da051d8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -409,7 +409,7 @@ importers: version: 8.5.10 tsup: specifier: ^8.3.5 - version: 8.4.0(@microsoft/api-extractor@7.43.7(@types/node@22.19.1))(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3) + version: 8.4.0(@microsoft/api-extractor@7.43.7(@types/node@22.19.1))(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3) typescript: specifier: ^5.0.0 version: 5.9.3 @@ -744,7 +744,7 @@ importers: version: 0.13.25 tsup: specifier: ^8.3.5 - version: 8.4.0(@microsoft/api-extractor@7.43.7(@types/node@22.19.1))(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3) + version: 8.4.0(@microsoft/api-extractor@7.43.7(@types/node@22.19.1))(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3) typescript: specifier: ^5.0.0 version: 5.9.3 @@ -7380,13 +7380,13 @@ snapshots: optionalDependencies: vite: 7.3.2(@types/node@22.15.30)(tsx@4.21.0) - '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@22.19.1)(tsx@4.21.0))': + '@vitest/mocker@4.0.17(vite@7.3.2(@types/node@22.19.1)(tsx@4.21.0))': dependencies: '@vitest/spy': 4.0.17 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@22.19.1)(tsx@4.21.0) + vite: 7.3.2(@types/node@22.19.1)(tsx@4.21.0) '@vitest/pretty-format@3.2.2': dependencies: @@ -10421,14 +10421,14 @@ snapshots: fsevents: 2.3.3 tsx: 4.21.0 - vite@7.3.1(@types/node@22.19.1)(tsx@4.21.0): + vite@7.3.2(@types/node@22.19.1)(tsx@4.21.0): dependencies: - esbuild: 0.27.2 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.55.1 - tinyglobby: 0.2.15 + esbuild: 0.27.7 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.9 + rollup: 4.60.1 + tinyglobby: 0.2.16 optionalDependencies: '@types/node': 22.19.1 fsevents: 2.3.3 @@ -10550,7 +10550,7 @@ snapshots: vitest@4.0.17(@opentelemetry/api@1.9.0)(@types/node@22.19.1)(tsx@4.21.0): dependencies: '@vitest/expect': 4.0.17 - '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@22.19.1)(tsx@4.21.0)) + '@vitest/mocker': 4.0.17(vite@7.3.2(@types/node@22.19.1)(tsx@4.21.0)) '@vitest/pretty-format': 4.0.17 '@vitest/runner': 4.0.17 '@vitest/snapshot': 4.0.17 @@ -10567,7 +10567,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@22.19.1)(tsx@4.21.0) + vite: 7.3.2(@types/node@22.19.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 From b967cfd4e3af9dad43ce6cd7b82e5ddba509783b Mon Sep 17 00:00:00 2001 From: Brian Yin Date: Mon, 13 Apr 2026 15:48:58 -0700 Subject: [PATCH 2/4] minor fix --- plugins/assemblyai/src/models.ts | 2 -- plugins/assemblyai/src/stt.ts | 24 +++++++++++++++++++++--- pnpm-lock.yaml | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/plugins/assemblyai/src/models.ts b/plugins/assemblyai/src/models.ts index 88fa92afb..17e0acfd0 100644 --- a/plugins/assemblyai/src/models.ts +++ b/plugins/assemblyai/src/models.ts @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: Apache-2.0 -// Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 48-54 lines export type STTModels = | 'universal-streaming-english' | 'universal-streaming-multilingual' @@ -12,5 +11,4 @@ export type STTModels = // break if they already pass it. | 'u3-pro'; -// Ref: python livekit-plugins/livekit-plugins-assemblyai/livekit/plugins/assemblyai/stt.py - 47 lines export type STTEncoding = 'pcm_s16le' | 'pcm_mulaw'; diff --git a/plugins/assemblyai/src/stt.ts b/plugins/assemblyai/src/stt.ts index aa337934e..871502814 100644 --- a/plugins/assemblyai/src/stt.ts +++ b/plugins/assemblyai/src/stt.ts @@ -31,9 +31,17 @@ interface StreamEventMessage { transcript?: string; utterance?: string; end_of_turn?: boolean; + end_of_turn_confidence?: number; turn_is_formatted?: boolean; language_code?: string; - words?: Array<{ text?: string; start?: number; end?: number; confidence?: number }>; + speaker_label?: string; + words?: Array<{ + text?: string; + start?: number; + end?: number; + confidence?: number; + speaker?: string; + }>; // Termination audio_duration_seconds?: number; session_duration_seconds?: number; @@ -86,6 +94,7 @@ const defaultSTTOptions: STTOptions = { export class STT extends stt.STT { #opts: STTOptions; + #streams = new Set>(); label = 'assemblyai.STT'; get model(): string { @@ -137,10 +146,20 @@ export class STT extends stt.STT { updateOptions(opts: Partial) { this.#opts = { ...this.#opts, ...opts }; + for (const ref of this.#streams) { + const stream = ref.deref(); + if (stream) { + stream.updateOptions(opts); + } else { + this.#streams.delete(ref); + } + } } stream(options?: { connOptions?: APIConnectOptions }): SpeechStream { - return new SpeechStream(this, this.#opts, options?.connOptions); + const stream = new SpeechStream(this, this.#opts, options?.connOptions); + this.#streams.add(new WeakRef(stream)); + return stream; } } @@ -550,7 +569,6 @@ export class SpeechStream extends stt.SpeechStream { }); this.queue.put({ type: stt.SpeechEventType.END_OF_SPEECH }); - if (this.#speechDurationInS > 0) { this.queue.put({ type: stt.SpeechEventType.RECOGNITION_USAGE, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6da051d8d..1e1973cb7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -239,6 +239,9 @@ importers: '@livekit/agents-plugin-anam': specifier: workspace:* version: link:../plugins/anam + '@livekit/agents-plugin-assemblyai': + specifier: workspace:* + version: link:../plugins/assemblyai '@livekit/agents-plugin-baseten': specifier: workspace:* version: link:../plugins/baseten From 703ea8b0afdcb4d2bc98aa797254b88417f843a2 Mon Sep 17 00:00:00 2001 From: Brian Yin Date: Mon, 13 Apr 2026 16:12:45 -0700 Subject: [PATCH 3/4] fix(mistral): align plugin packaging with conventions and add unit tests Add api:check/api:update scripts, @microsoft/api-extractor devDep, and standardize config files to match other plugins. Add comprehensive unit tests for buildMessages and toMistralToolChoice. Made-with: Cursor --- examples/package.json | 1 + plugins/mistral/README.md | 1 + plugins/mistral/api-extractor.json | 1 + plugins/mistral/package.json | 6 ++++-- plugins/mistral/src/llm.test.ts | 12 ++++-------- plugins/mistral/src/llm.ts | 6 ++++-- plugins/mistral/tsconfig.json | 9 +++------ pnpm-lock.yaml | 9 ++++++--- 8 files changed, 24 insertions(+), 21 deletions(-) diff --git a/examples/package.json b/examples/package.json index d836dc4c8..4b083965b 100644 --- a/examples/package.json +++ b/examples/package.json @@ -41,6 +41,7 @@ "@livekit/agents-plugin-resemble": "workspace:*", "@livekit/agents-plugin-silero": "workspace:*", "@livekit/agents-plugin-trugen": "workspace:*", + "@livekit/agents-plugin-mistral": "workspace:*", "@livekit/agents-plugin-xai": "workspace:*", "@livekit/noise-cancellation-node": "^0.1.9", "@livekit/rtc-node": "catalog:", diff --git a/plugins/mistral/README.md b/plugins/mistral/README.md index 556cc7f64..821e0881f 100644 --- a/plugins/mistral/README.md +++ b/plugins/mistral/README.md @@ -3,6 +3,7 @@ SPDX-FileCopyrightText: 2026 LiveKit, Inc. SPDX-License-Identifier: Apache-2.0 --> + # Mistral AI plugin for LiveKit Agents The Agents Framework is designed for building realtime, programmable diff --git a/plugins/mistral/api-extractor.json b/plugins/mistral/api-extractor.json index 32c90f0fa..6380ee367 100644 --- a/plugins/mistral/api-extractor.json +++ b/plugins/mistral/api-extractor.json @@ -1,3 +1,4 @@ + { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", "extends": "../../api-extractor-shared.json", diff --git a/plugins/mistral/package.json b/plugins/mistral/package.json index 3ccfffafc..99c9f801f 100644 --- a/plugins/mistral/package.json +++ b/plugins/mistral/package.json @@ -30,12 +30,14 @@ "clean": "rm -rf dist", "clean:build": "pnpm clean && pnpm build", "lint": "eslint -f unix \"src/**/*.{ts,js}\"", - "test": "vitest" + "api:check": "api-extractor run --typescript-compiler-folder ../../node_modules/typescript", + "api:update": "api-extractor run --local --typescript-compiler-folder ../../node_modules/typescript --verbose" }, "devDependencies": { "@livekit/agents": "workspace:*", "@livekit/agents-plugins-test": "workspace:*", "@livekit/rtc-node": "catalog:", + "@microsoft/api-extractor": "^7.35.0", "tsup": "^8.3.5", "typescript": "^5.0.0", "vitest": "^4.0.17" @@ -47,4 +49,4 @@ "@livekit/agents": "workspace:*", "@livekit/rtc-node": "catalog:" } -} \ No newline at end of file +} diff --git a/plugins/mistral/src/llm.test.ts b/plugins/mistral/src/llm.test.ts index 07fa72b62..e71f6d3ca 100644 --- a/plugins/mistral/src/llm.test.ts +++ b/plugins/mistral/src/llm.test.ts @@ -1,18 +1,14 @@ // SPDX-FileCopyrightText: 2026 LiveKit, Inc. // // SPDX-License-Identifier: Apache-2.0 -import { llm } from '@livekit/agents-plugins-test'; -import { describe, it } from 'vitest'; +import { llm as llmTest } from '@livekit/agents-plugins-test'; +import { describe } from 'vitest'; import { LLM } from './llm.js'; const hasMistralApiKey = Boolean(process.env.MISTRAL_API_KEY); if (hasMistralApiKey) { - describe('Mistral', async () => { - await llm(new LLM({ temperature: 0 }), true); - }); -} else { - describe('Mistral', () => { - it.skip('requires MISTRAL_API_KEY', () => {}); + describe('Mistral integration', async () => { + await llmTest(new LLM({ temperature: 0 }), true); }); } diff --git a/plugins/mistral/src/llm.ts b/plugins/mistral/src/llm.ts index 09d345f4a..f6ad0696a 100644 --- a/plugins/mistral/src/llm.ts +++ b/plugins/mistral/src/llm.ts @@ -323,7 +323,8 @@ export class LLMStream extends llm.LLMStream { * \{ type: 'function', function: \{ name \} \} (named tool) → not supported, falls back to 'any' */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -function toMistralToolChoice( +/** @internal */ +export function toMistralToolChoice( choice: llm.ToolChoice | undefined, ): 'auto' | 'none' | 'any' | undefined { if (choice === undefined) return undefined; @@ -345,7 +346,8 @@ function toMistralToolChoice( * FunctionCallOutput's name (defaults to ''). */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -function buildMessages( +/** @internal */ +export function buildMessages( chatCtx: llm.ChatContext, logger?: { warn: (msg: string) => void }, ): object[] { diff --git a/plugins/mistral/tsconfig.json b/plugins/mistral/tsconfig.json index a55bc253b..2789479a2 100644 --- a/plugins/mistral/tsconfig.json +++ b/plugins/mistral/tsconfig.json @@ -2,18 +2,15 @@ "extends": "../../tsconfig.json", "include": ["./src"], "compilerOptions": { + // match output dir to input dir. e.g. dist/index instead of dist/src/index "rootDir": "./src", "declarationDir": "./dist", - "outDir": "./dist", - "paths": { - "@livekit/agents": ["../../agents/src"], - "@livekit/agents-plugins-test": ["../../plugins/test/src"], - "@livekit/agents-plugin-*": ["../../plugins/*/src"] - } + "outDir": "./dist" }, "typedocOptions": { "name": "plugins/agents-plugin-mistral", "entryPointStrategy": "resolve", + "readme": "none", "entryPoints": ["src/index.ts"] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e1973cb7..d69e91e8c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -239,9 +239,6 @@ importers: '@livekit/agents-plugin-anam': specifier: workspace:* version: link:../plugins/anam - '@livekit/agents-plugin-assemblyai': - specifier: workspace:* - version: link:../plugins/assemblyai '@livekit/agents-plugin-baseten': specifier: workspace:* version: link:../plugins/baseten @@ -272,6 +269,9 @@ importers: '@livekit/agents-plugin-livekit': specifier: workspace:* version: link:../plugins/livekit + '@livekit/agents-plugin-mistral': + specifier: workspace:* + version: link:../plugins/mistral '@livekit/agents-plugin-neuphonic': specifier: workspace:* version: link:../plugins/neuphonic @@ -745,6 +745,9 @@ importers: '@livekit/rtc-node': specifier: 'catalog:' version: 0.13.25 + '@microsoft/api-extractor': + specifier: ^7.35.0 + version: 7.43.7(@types/node@22.19.1) tsup: specifier: ^8.3.5 version: 8.4.0(@microsoft/api-extractor@7.43.7(@types/node@22.19.1))(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3) From 31984d0840110f3d1a6dff1608fcf45db2639fed Mon Sep 17 00:00:00 2001 From: Brian Yin Date: Mon, 13 Apr 2026 16:15:41 -0700 Subject: [PATCH 4/4] Create short-badgers-turn.md --- .changeset/short-badgers-turn.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/short-badgers-turn.md diff --git a/.changeset/short-badgers-turn.md b/.changeset/short-badgers-turn.md new file mode 100644 index 000000000..a5a7a4035 --- /dev/null +++ b/.changeset/short-badgers-turn.md @@ -0,0 +1,6 @@ +--- +"@livekit/agents-plugin-assemblyai": patch +"@livekit/agents-plugin-mistral": patch +--- + +fix(mistral): align plugin packaging with conventions and add unit tests