@livekit/agents 1.0.2 → 1.0.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.cjs +2 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/ipc/job_proc_lazy_main.cjs +3 -2
- package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.js +4 -3
- package/dist/ipc/job_proc_lazy_main.js.map +1 -1
- package/dist/job.cjs +20 -14
- package/dist/job.cjs.map +1 -1
- package/dist/job.d.cts +11 -5
- package/dist/job.d.ts +11 -5
- package/dist/job.d.ts.map +1 -1
- package/dist/job.js +17 -12
- package/dist/job.js.map +1 -1
- package/dist/tokenize/basic/hyphenator.cjs.map +1 -1
- package/dist/tokenize/basic/hyphenator.js.map +1 -1
- package/dist/utils.cjs +77 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +21 -0
- package/dist/utils.d.ts +21 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +76 -1
- package/dist/utils.js.map +1 -1
- package/dist/voice/agent_activity.cjs +112 -71
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +112 -71
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +9 -2
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +9 -2
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/avatar/datastream_io.cjs +204 -0
- package/dist/voice/avatar/datastream_io.cjs.map +1 -0
- package/dist/voice/avatar/datastream_io.d.cts +37 -0
- package/dist/voice/avatar/datastream_io.d.ts +37 -0
- package/dist/voice/avatar/datastream_io.d.ts.map +1 -0
- package/dist/voice/avatar/datastream_io.js +188 -0
- package/dist/voice/avatar/datastream_io.js.map +1 -0
- package/dist/{multimodal → voice/avatar}/index.cjs +4 -4
- package/dist/voice/avatar/index.cjs.map +1 -0
- package/dist/voice/avatar/index.d.cts +2 -0
- package/dist/voice/avatar/index.d.ts +2 -0
- package/dist/voice/avatar/index.d.ts.map +1 -0
- package/dist/voice/avatar/index.js +2 -0
- package/dist/voice/avatar/index.js.map +1 -0
- package/dist/voice/index.cjs +2 -0
- package/dist/voice/index.cjs.map +1 -1
- package/dist/voice/index.d.cts +1 -0
- package/dist/voice/index.d.ts +1 -0
- package/dist/voice/index.d.ts.map +1 -1
- package/dist/voice/index.js +1 -0
- package/dist/voice/index.js.map +1 -1
- package/dist/voice/io.cjs.map +1 -1
- package/dist/voice/io.d.cts +1 -1
- package/dist/voice/io.d.ts +1 -1
- package/dist/voice/io.d.ts.map +1 -1
- package/dist/voice/io.js.map +1 -1
- package/dist/voice/room_io/_input.cjs +2 -1
- package/dist/voice/room_io/_input.cjs.map +1 -1
- package/dist/voice/room_io/_input.d.ts.map +1 -1
- package/dist/voice/room_io/_input.js +2 -1
- package/dist/voice/room_io/_input.js.map +1 -1
- package/dist/voice/run_context.cjs +13 -0
- package/dist/voice/run_context.cjs.map +1 -1
- package/dist/voice/run_context.d.cts +10 -0
- package/dist/voice/run_context.d.ts +10 -0
- package/dist/voice/run_context.d.ts.map +1 -1
- package/dist/voice/run_context.js +13 -0
- package/dist/voice/run_context.js.map +1 -1
- package/dist/voice/speech_handle.cjs +152 -30
- package/dist/voice/speech_handle.cjs.map +1 -1
- package/dist/voice/speech_handle.d.cts +67 -16
- package/dist/voice/speech_handle.d.ts +67 -16
- package/dist/voice/speech_handle.d.ts.map +1 -1
- package/dist/voice/speech_handle.js +153 -31
- package/dist/voice/speech_handle.js.map +1 -1
- package/dist/worker.cjs +4 -1
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +4 -1
- package/dist/worker.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +2 -3
- package/src/ipc/job_proc_lazy_main.ts +6 -3
- package/src/job.ts +27 -12
- package/src/tokenize/basic/hyphenator.ts +1 -1
- package/src/utils.ts +121 -1
- package/src/voice/agent_activity.ts +128 -78
- package/src/voice/agent_session.ts +11 -2
- package/src/voice/avatar/datastream_io.ts +247 -0
- package/src/voice/avatar/index.ts +4 -0
- package/src/voice/index.ts +2 -0
- package/src/voice/io.ts +1 -1
- package/src/voice/room_io/_input.ts +8 -3
- package/src/voice/run_context.ts +16 -2
- package/src/voice/speech_handle.ts +183 -38
- package/src/worker.ts +5 -1
- package/dist/multimodal/agent_playout.cjs +0 -233
- package/dist/multimodal/agent_playout.cjs.map +0 -1
- package/dist/multimodal/agent_playout.d.cts +0 -34
- package/dist/multimodal/agent_playout.d.ts +0 -34
- package/dist/multimodal/agent_playout.d.ts.map +0 -1
- package/dist/multimodal/agent_playout.js +0 -207
- package/dist/multimodal/agent_playout.js.map +0 -1
- package/dist/multimodal/index.cjs.map +0 -1
- package/dist/multimodal/index.d.cts +0 -2
- package/dist/multimodal/index.d.ts +0 -2
- package/dist/multimodal/index.d.ts.map +0 -1
- package/dist/multimodal/index.js +0 -2
- package/dist/multimodal/index.js.map +0 -1
- package/src/multimodal/agent_playout.ts +0 -266
- package/src/multimodal/index.ts +0 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/avatar/datastream_io.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Mutex } from '@livekit/mutex';\nimport {\n type AudioFrame,\n type ByteStreamWriter,\n type Room,\n RoomEvent,\n type RpcInvocationData,\n type TrackKind,\n} from '@livekit/rtc-node';\nimport { log } from '../../log.js';\nimport {\n Future,\n Task,\n shortuuid,\n waitForParticipant,\n waitForTrackPublication,\n} from '../../utils.js';\nimport { AudioOutput, type PlaybackFinishedEvent } from '../io.js';\n\nconst RPC_CLEAR_BUFFER = 'lk.clear_buffer';\nconst RPC_PLAYBACK_FINISHED = 'lk.playback_finished';\nconst AUDIO_STREAM_TOPIC = 'lk.audio_stream';\n\nexport interface DataStreamAudioOutputOptions {\n room: Room;\n destinationIdentity: string;\n sampleRate?: number;\n waitRemoteTrack?: TrackKind;\n}\n\n/**\n * AudioOutput implementation that streams audio to a remote avatar worker using LiveKit DataStream.\n */\nexport class DataStreamAudioOutput extends AudioOutput {\n static _playbackFinishedRpcRegistered: boolean = false;\n static _playbackFinishedHandlers: Record<string, (data: RpcInvocationData) => string> = {};\n\n private room: Room;\n private destinationIdentity: string;\n private roomConnectedFuture: Future<void>;\n private waitRemoteTrack?: TrackKind;\n private streamWriter?: ByteStreamWriter;\n private pushedDuration: number = 0;\n private started: boolean = false;\n private lock = new Mutex();\n private startTask?: Task<void>;\n\n #logger = log();\n\n constructor(opts: DataStreamAudioOutputOptions) {\n super(opts.sampleRate, undefined);\n\n const { room, destinationIdentity, sampleRate, waitRemoteTrack } = opts;\n this.room = room;\n this.destinationIdentity = destinationIdentity;\n this.sampleRate = sampleRate;\n this.waitRemoteTrack = waitRemoteTrack;\n\n const onRoomConnected = async () => {\n if (this.startTask) return;\n\n await this.roomConnectedFuture.await;\n\n // register the rpc method right after the room is connected\n DataStreamAudioOutput.registerPlaybackFinishedRpc({\n room,\n callerIdentity: this.destinationIdentity,\n handler: (data) => this.handlePlaybackFinished(data),\n });\n\n this.startTask = Task.from(({ signal }) => this._start(signal));\n };\n\n this.roomConnectedFuture = new Future<void>();\n\n this.room.on(RoomEvent.ConnectionStateChanged, (_) => {\n if (room.isConnected && !this.roomConnectedFuture.done) {\n this.roomConnectedFuture.resolve(undefined);\n }\n });\n\n if (this.room.isConnected) {\n this.roomConnectedFuture.resolve(undefined);\n }\n\n onRoomConnected();\n }\n\n private async _start(_abortSignal: AbortSignal) {\n const unlock = await this.lock.lock();\n\n try {\n if (this.started) return;\n\n await this.roomConnectedFuture.await;\n\n this.#logger.debug(\n {\n identity: this.destinationIdentity,\n },\n 'waiting for the remote participant',\n );\n\n await waitForParticipant({\n room: this.room,\n identity: this.destinationIdentity,\n });\n\n if (this.waitRemoteTrack) {\n this.#logger.debug(\n {\n identity: this.destinationIdentity,\n kind: this.waitRemoteTrack,\n },\n 'waiting for the remote track',\n );\n\n await waitForTrackPublication({\n room: this.room,\n identity: this.destinationIdentity,\n kind: this.waitRemoteTrack,\n });\n }\n\n this.#logger.debug(\n {\n identity: this.destinationIdentity,\n },\n 'remote participant ready',\n );\n\n this.started = true;\n } finally {\n unlock();\n }\n }\n\n async captureFrame(frame: AudioFrame): Promise<void> {\n if (!this.startTask) {\n this.startTask = Task.from(({ signal }) => this._start(signal));\n }\n\n await this.startTask.result;\n await super.captureFrame(frame);\n\n if (!this.streamWriter) {\n this.streamWriter = await this.room.localParticipant!.streamBytes({\n name: shortuuid('AUDIO_'),\n topic: AUDIO_STREAM_TOPIC,\n destinationIdentities: [this.destinationIdentity],\n attributes: {\n sample_rate: frame.sampleRate.toString(),\n num_channels: frame.channels.toString(),\n },\n });\n this.pushedDuration = 0;\n }\n\n // frame.data is a Int16Array, write accepts a Uint8Array\n await this.streamWriter.write(new Uint8Array(frame.data.buffer));\n this.pushedDuration += frame.samplesPerChannel / frame.sampleRate;\n }\n\n flush(): void {\n super.flush();\n\n if (this.streamWriter === undefined || !this.started) {\n return;\n }\n\n this.streamWriter.close().finally(() => {\n this.streamWriter = undefined;\n });\n }\n\n clearBuffer(): void {\n if (!this.started) return;\n\n this.room.localParticipant!.performRpc({\n destinationIdentity: this.destinationIdentity,\n method: RPC_CLEAR_BUFFER,\n payload: '',\n });\n }\n\n private handlePlaybackFinished(data: RpcInvocationData): string {\n if (data.callerIdentity !== this.destinationIdentity) {\n this.#logger.warn(\n {\n callerIdentity: data.callerIdentity,\n destinationIdentity: this.destinationIdentity,\n },\n 'playback finished event received from unexpected participant',\n );\n return 'reject';\n }\n\n this.#logger.info(\n {\n callerIdentity: data.callerIdentity,\n },\n 'playback finished event received',\n );\n\n const playbackFinishedEvent = JSON.parse(data.payload) as PlaybackFinishedEvent;\n this.onPlaybackFinished(playbackFinishedEvent);\n return 'ok';\n }\n\n static registerPlaybackFinishedRpc({\n room,\n callerIdentity,\n handler,\n }: {\n room: Room;\n callerIdentity: string;\n handler: (data: RpcInvocationData) => string;\n }) {\n DataStreamAudioOutput._playbackFinishedHandlers[callerIdentity] = handler;\n\n if (DataStreamAudioOutput._playbackFinishedRpcRegistered) {\n return;\n }\n\n const rpcHandler = async (data: RpcInvocationData): Promise<string> => {\n const handler = DataStreamAudioOutput._playbackFinishedHandlers[data.callerIdentity];\n if (!handler) {\n log().warn(\n {\n callerIdentity: data.callerIdentity,\n expectedIdentities: Object.keys(DataStreamAudioOutput._playbackFinishedHandlers),\n },\n 'playback finished event received from unexpected participant',\n );\n\n return 'reject';\n }\n return handler(data);\n };\n\n room.localParticipant?.registerRpcMethod(RPC_PLAYBACK_FINISHED, rpcHandler);\n DataStreamAudioOutput._playbackFinishedRpcRegistered = true;\n }\n}\n"],"mappings":"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","names":["handler"]}
|
|
@@ -13,11 +13,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
13
13
|
};
|
|
14
14
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
15
15
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
16
|
-
var
|
|
17
|
-
module.exports = __toCommonJS(
|
|
18
|
-
__reExport(
|
|
16
|
+
var avatar_exports = {};
|
|
17
|
+
module.exports = __toCommonJS(avatar_exports);
|
|
18
|
+
__reExport(avatar_exports, require("./datastream_io.cjs"), module.exports);
|
|
19
19
|
// Annotate the CommonJS export names for ESM import in node:
|
|
20
20
|
0 && (module.exports = {
|
|
21
|
-
...require("./
|
|
21
|
+
...require("./datastream_io.cjs")
|
|
22
22
|
});
|
|
23
23
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/avatar/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport * from './datastream_io.js';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAGA,2BAAc,+BAHd;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/voice/avatar/index.ts"],"names":[],"mappings":"AAGA,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/avatar/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport * from './datastream_io.js';\n"],"mappings":"AAGA,cAAc;","names":[]}
|
package/dist/voice/index.cjs
CHANGED
|
@@ -27,6 +27,7 @@ __export(voice_exports, {
|
|
|
27
27
|
module.exports = __toCommonJS(voice_exports);
|
|
28
28
|
var import_agent = require("./agent.cjs");
|
|
29
29
|
var import_agent_session = require("./agent_session.cjs");
|
|
30
|
+
__reExport(voice_exports, require("./avatar/index.cjs"), module.exports);
|
|
30
31
|
__reExport(voice_exports, require("./events.cjs"), module.exports);
|
|
31
32
|
var import_run_context = require("./run_context.cjs");
|
|
32
33
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -35,6 +36,7 @@ var import_run_context = require("./run_context.cjs");
|
|
|
35
36
|
AgentSession,
|
|
36
37
|
RunContext,
|
|
37
38
|
StopResponse,
|
|
39
|
+
...require("./avatar/index.cjs"),
|
|
38
40
|
...require("./events.cjs")
|
|
39
41
|
});
|
|
40
42
|
//# sourceMappingURL=index.cjs.map
|
package/dist/voice/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\nexport * from './events.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAA2E;AAC3E,2BAAuD;
|
|
1
|
+
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\n\nexport * from './avatar/index.js';\nexport * from './events.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAA2E;AAC3E,2BAAuD;AAEvD,0BAAc,8BANd;AAOA,0BAAc,wBAPd;AAQA,yBAA2B;","names":[]}
|
package/dist/voice/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';
|
|
2
2
|
export { AgentSession, type AgentSessionOptions } from './agent_session.js';
|
|
3
|
+
export * from './avatar/index.js';
|
|
3
4
|
export * from './events.js';
|
|
4
5
|
export { RunContext } from './run_context.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/voice/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';
|
|
2
2
|
export { AgentSession, type AgentSessionOptions } from './agent_session.js';
|
|
3
|
+
export * from './avatar/index.js';
|
|
3
4
|
export * from './events.js';
|
|
4
5
|
export { RunContext } from './run_context.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voice/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voice/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/voice/index.js
CHANGED
package/dist/voice/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\nexport * from './events.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":"AAGA,SAAS,OAAO,oBAA2D;AAC3E,SAAS,oBAA8C;
|
|
1
|
+
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\n\nexport * from './avatar/index.js';\nexport * from './events.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":"AAGA,SAAS,OAAO,oBAA2D;AAC3E,SAAS,oBAA8C;AAEvD,cAAc;AACd,cAAc;AACd,SAAS,kBAAkB;","names":[]}
|
package/dist/voice/io.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/io.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'node:events';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { ChatContext } from '../llm/chat_context.js';\nimport type { ChatChunk } from '../llm/llm.js';\nimport type { ToolContext } from '../llm/tool_context.js';\nimport { log } from '../log.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport type { SpeechEvent } from '../stt/stt.js';\nimport { Future } from '../utils.js';\nimport type { ModelSettings } from './agent.js';\n\nexport type STTNode = (\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<SpeechEvent | string> | null>;\n\nexport type LLMNode = (\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<ChatChunk | string> | null>;\n\nexport type TTSNode = (\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<AudioFrame> | null>;\nexport abstract class AudioInput {\n protected deferredStream: DeferredReadableStream<AudioFrame> =\n new DeferredReadableStream<AudioFrame>();\n\n get stream(): ReadableStream<AudioFrame> {\n return this.deferredStream.stream;\n }\n\n onAttached(): void {}\n\n onDetached(): void {}\n}\n\nexport abstract class AudioOutput extends EventEmitter {\n static readonly EVENT_PLAYBACK_FINISHED = 'playbackFinished';\n\n private playbackFinishedFuture: Future<void> = new Future();\n private _capturing: boolean = false;\n private playbackFinishedCount: number = 0;\n private playbackSegmentsCount: number = 0;\n private lastPlaybackEvent: PlaybackFinishedEvent = {\n playbackPosition: 0,\n interrupted: false,\n };\n protected logger = log();\n\n constructor(\n readonly sampleRate?: number,\n protected readonly nextInChain?: AudioOutput,\n ) {\n super();\n if (this.nextInChain) {\n this.nextInChain.on(AudioOutput.EVENT_PLAYBACK_FINISHED, (ev: PlaybackFinishedEvent) =>\n this.onPlaybackFinished(ev),\n );\n }\n }\n\n /**\n * Capture an audio frame for playback, frames can be pushed faster than real-time\n */\n async captureFrame(_frame: AudioFrame): Promise<void> {\n if (!this._capturing) {\n this._capturing = true;\n this.playbackSegmentsCount++;\n }\n }\n\n /**\n * Wait for the past audio segments to finish playing out.\n *\n * @returns The event that was emitted when the audio finished playing out (only the last segment information)\n */\n async waitForPlayout(): Promise<PlaybackFinishedEvent> {\n const target = this.playbackSegmentsCount;\n\n while (this.playbackFinishedCount < target) {\n await this.playbackFinishedFuture.await;\n this.playbackFinishedFuture = new Future();\n }\n\n return this.lastPlaybackEvent;\n }\n\n /**\n * Developers building audio sinks must call this method when a playback/segment is finished.\n * Segments are segmented by calls to flush() or clearBuffer()\n */\n onPlaybackFinished(options: PlaybackFinishedEvent) {\n if (this.playbackFinishedCount >= this.playbackSegmentsCount) {\n this.logger.warn('playback_finished called more times than playback segments were captured');\n return;\n }\n\n this.lastPlaybackEvent = options;\n this.playbackFinishedCount++;\n this.playbackFinishedFuture.resolve();\n this.emit(AudioOutput.EVENT_PLAYBACK_FINISHED, options);\n }\n\n flush(): void {\n this._capturing = false;\n }\n\n /**\n * Clear the buffer, stopping playback immediately\n */\n abstract clearBuffer(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport interface PlaybackFinishedEvent {\n // How much of the audio was played back\n playbackPosition: number;\n // Interrupted is True if playback was interrupted (clearBuffer() was called)\n interrupted: boolean;\n // Transcript synced with playback; may be partial if the audio was interrupted\n // When null, the transcript is not synchronized with the playback\n synchronizedTranscript?: string;\n}\n\nexport abstract class TextOutput {\n constructor(protected readonly nextInChain?: TextOutput) {}\n\n /**\n * Capture a text segment (Used by the output of LLM nodes)\n */\n abstract captureText(text: string): Promise<void>;\n\n /**\n * Mark the current text segment as complete (e.g LLM generation is complete)\n */\n abstract flush(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport class AgentInput {\n private _audioStream: AudioInput | null = null;\n // enabled by default\n private _audioEnabled: boolean = true;\n\n constructor(private readonly audioChanged: () => void) {}\n\n setAudioEnabled(enable: boolean): void {\n if (enable === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enable;\n\n if (!this._audioStream) {\n return;\n }\n\n if (enable) {\n this._audioStream.onAttached();\n } else {\n this._audioStream.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get audio(): AudioInput | null {\n return this._audioStream;\n }\n\n set audio(stream: AudioInput | null) {\n this._audioStream = stream;\n this.audioChanged();\n }\n}\n\nexport class AgentOutput {\n private _audioSink: AudioOutput | null = null;\n private _transcriptionSink: TextOutput | null = null;\n private _audioEnabled: boolean = true;\n private _transcriptionEnabled: boolean = true;\n\n constructor(\n private readonly audioChanged: () => void,\n private readonly transcriptionChanged: () => void,\n ) {}\n\n setAudioEnabled(enabled: boolean): void {\n if (enabled === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enabled;\n\n if (!this._audioSink) {\n return;\n }\n\n if (enabled) {\n this._audioSink.onAttached();\n } else {\n this._audioSink.onDetached();\n }\n }\n\n setTranscriptionEnabled(enabled: boolean): void {\n if (enabled === this._transcriptionEnabled) {\n return;\n }\n\n this._transcriptionEnabled = enabled;\n\n if (!this._transcriptionSink) {\n return;\n }\n\n if (enabled) {\n this._transcriptionSink.onAttached();\n } else {\n this._transcriptionSink.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get transcriptionEnabled(): boolean {\n return this._transcriptionEnabled;\n }\n\n get audio(): AudioOutput | null {\n return this._audioSink;\n }\n\n set audio(sink: AudioOutput | null) {\n if (sink === this._audioSink) {\n return;\n }\n\n if (this._audioSink) {\n this._audioSink.onDetached();\n }\n\n this._audioSink = sink;\n this.audioChanged();\n\n if (this._audioSink) {\n this._audioSink.onAttached();\n }\n }\n\n get transcription(): TextOutput | null {\n return this._transcriptionSink;\n }\n\n set transcription(sink: TextOutput | null) {\n if (sink === this._transcriptionSink) {\n return;\n }\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onDetached();\n }\n\n this._transcriptionSink = sink;\n this.transcriptionChanged();\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onAttached();\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/io.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'node:events';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { ChatContext } from '../llm/chat_context.js';\nimport type { ChatChunk } from '../llm/llm.js';\nimport type { ToolContext } from '../llm/tool_context.js';\nimport { log } from '../log.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport type { SpeechEvent } from '../stt/stt.js';\nimport { Future } from '../utils.js';\nimport type { ModelSettings } from './agent.js';\n\nexport type STTNode = (\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<SpeechEvent | string> | null>;\n\nexport type LLMNode = (\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<ChatChunk | string> | null>;\n\nexport type TTSNode = (\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<AudioFrame> | null>;\nexport abstract class AudioInput {\n protected deferredStream: DeferredReadableStream<AudioFrame> =\n new DeferredReadableStream<AudioFrame>();\n\n get stream(): ReadableStream<AudioFrame> {\n return this.deferredStream.stream;\n }\n\n onAttached(): void {}\n\n onDetached(): void {}\n}\n\nexport abstract class AudioOutput extends EventEmitter {\n static readonly EVENT_PLAYBACK_FINISHED = 'playbackFinished';\n\n private playbackFinishedFuture: Future<void> = new Future();\n private _capturing: boolean = false;\n private playbackFinishedCount: number = 0;\n private playbackSegmentsCount: number = 0;\n private lastPlaybackEvent: PlaybackFinishedEvent = {\n playbackPosition: 0,\n interrupted: false,\n };\n protected logger = log();\n\n constructor(\n public sampleRate?: number,\n protected readonly nextInChain?: AudioOutput,\n ) {\n super();\n if (this.nextInChain) {\n this.nextInChain.on(AudioOutput.EVENT_PLAYBACK_FINISHED, (ev: PlaybackFinishedEvent) =>\n this.onPlaybackFinished(ev),\n );\n }\n }\n\n /**\n * Capture an audio frame for playback, frames can be pushed faster than real-time\n */\n async captureFrame(_frame: AudioFrame): Promise<void> {\n if (!this._capturing) {\n this._capturing = true;\n this.playbackSegmentsCount++;\n }\n }\n\n /**\n * Wait for the past audio segments to finish playing out.\n *\n * @returns The event that was emitted when the audio finished playing out (only the last segment information)\n */\n async waitForPlayout(): Promise<PlaybackFinishedEvent> {\n const target = this.playbackSegmentsCount;\n\n while (this.playbackFinishedCount < target) {\n await this.playbackFinishedFuture.await;\n this.playbackFinishedFuture = new Future();\n }\n\n return this.lastPlaybackEvent;\n }\n\n /**\n * Developers building audio sinks must call this method when a playback/segment is finished.\n * Segments are segmented by calls to flush() or clearBuffer()\n */\n onPlaybackFinished(options: PlaybackFinishedEvent) {\n if (this.playbackFinishedCount >= this.playbackSegmentsCount) {\n this.logger.warn('playback_finished called more times than playback segments were captured');\n return;\n }\n\n this.lastPlaybackEvent = options;\n this.playbackFinishedCount++;\n this.playbackFinishedFuture.resolve();\n this.emit(AudioOutput.EVENT_PLAYBACK_FINISHED, options);\n }\n\n flush(): void {\n this._capturing = false;\n }\n\n /**\n * Clear the buffer, stopping playback immediately\n */\n abstract clearBuffer(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport interface PlaybackFinishedEvent {\n // How much of the audio was played back\n playbackPosition: number;\n // Interrupted is True if playback was interrupted (clearBuffer() was called)\n interrupted: boolean;\n // Transcript synced with playback; may be partial if the audio was interrupted\n // When null, the transcript is not synchronized with the playback\n synchronizedTranscript?: string;\n}\n\nexport abstract class TextOutput {\n constructor(protected readonly nextInChain?: TextOutput) {}\n\n /**\n * Capture a text segment (Used by the output of LLM nodes)\n */\n abstract captureText(text: string): Promise<void>;\n\n /**\n * Mark the current text segment as complete (e.g LLM generation is complete)\n */\n abstract flush(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport class AgentInput {\n private _audioStream: AudioInput | null = null;\n // enabled by default\n private _audioEnabled: boolean = true;\n\n constructor(private readonly audioChanged: () => void) {}\n\n setAudioEnabled(enable: boolean): void {\n if (enable === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enable;\n\n if (!this._audioStream) {\n return;\n }\n\n if (enable) {\n this._audioStream.onAttached();\n } else {\n this._audioStream.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get audio(): AudioInput | null {\n return this._audioStream;\n }\n\n set audio(stream: AudioInput | null) {\n this._audioStream = stream;\n this.audioChanged();\n }\n}\n\nexport class AgentOutput {\n private _audioSink: AudioOutput | null = null;\n private _transcriptionSink: TextOutput | null = null;\n private _audioEnabled: boolean = true;\n private _transcriptionEnabled: boolean = true;\n\n constructor(\n private readonly audioChanged: () => void,\n private readonly transcriptionChanged: () => void,\n ) {}\n\n setAudioEnabled(enabled: boolean): void {\n if (enabled === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enabled;\n\n if (!this._audioSink) {\n return;\n }\n\n if (enabled) {\n this._audioSink.onAttached();\n } else {\n this._audioSink.onDetached();\n }\n }\n\n setTranscriptionEnabled(enabled: boolean): void {\n if (enabled === this._transcriptionEnabled) {\n return;\n }\n\n this._transcriptionEnabled = enabled;\n\n if (!this._transcriptionSink) {\n return;\n }\n\n if (enabled) {\n this._transcriptionSink.onAttached();\n } else {\n this._transcriptionSink.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get transcriptionEnabled(): boolean {\n return this._transcriptionEnabled;\n }\n\n get audio(): AudioOutput | null {\n return this._audioSink;\n }\n\n set audio(sink: AudioOutput | null) {\n if (sink === this._audioSink) {\n return;\n }\n\n if (this._audioSink) {\n this._audioSink.onDetached();\n }\n\n this._audioSink = sink;\n this.audioChanged();\n\n if (this._audioSink) {\n this._audioSink.onAttached();\n }\n }\n\n get transcription(): TextOutput | null {\n return this._transcriptionSink;\n }\n\n set transcription(sink: TextOutput | null) {\n if (sink === this._transcriptionSink) {\n return;\n }\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onDetached();\n }\n\n this._transcriptionSink = sink;\n this.transcriptionChanged();\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onAttached();\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/voice/io.d.cts
CHANGED
|
@@ -19,7 +19,7 @@ export declare abstract class AudioInput {
|
|
|
19
19
|
onDetached(): void;
|
|
20
20
|
}
|
|
21
21
|
export declare abstract class AudioOutput extends EventEmitter {
|
|
22
|
-
|
|
22
|
+
sampleRate?: number | undefined;
|
|
23
23
|
protected readonly nextInChain?: AudioOutput | undefined;
|
|
24
24
|
static readonly EVENT_PLAYBACK_FINISHED = "playbackFinished";
|
|
25
25
|
private playbackFinishedFuture;
|
package/dist/voice/io.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare abstract class AudioInput {
|
|
|
19
19
|
onDetached(): void;
|
|
20
20
|
}
|
|
21
21
|
export declare abstract class AudioOutput extends EventEmitter {
|
|
22
|
-
|
|
22
|
+
sampleRate?: number | undefined;
|
|
23
23
|
protected readonly nextInChain?: AudioOutput | undefined;
|
|
24
24
|
static readonly EVENT_PLAYBACK_FINISHED = "playbackFinished";
|
|
25
25
|
private playbackFinishedFuture;
|
package/dist/voice/io.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/voice/io.ts"],"names":[],"mappings":";;AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,OAAO,GAAG,CACpB,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,EACjC,aAAa,EAAE,aAAa,KACzB,OAAO,CAAC,cAAc,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AAE1D,MAAM,MAAM,OAAO,GAAG,CACpB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,aAAa,KACzB,OAAO,CAAC,cAAc,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AAExD,MAAM,MAAM,OAAO,GAAG,CACpB,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAC5B,aAAa,EAAE,aAAa,KACzB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;AAChD,8BAAsB,UAAU;IAC9B,SAAS,CAAC,cAAc,EAAE,sBAAsB,CAAC,UAAU,CAAC,CACjB;IAE3C,IAAI,MAAM,IAAI,cAAc,CAAC,UAAU,CAAC,CAEvC;IAED,UAAU,IAAI,IAAI;IAElB,UAAU,IAAI,IAAI;CACnB;AAED,8BAAsB,WAAY,SAAQ,YAAY;
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/voice/io.ts"],"names":[],"mappings":"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"}
|
package/dist/voice/io.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/io.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'node:events';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { ChatContext } from '../llm/chat_context.js';\nimport type { ChatChunk } from '../llm/llm.js';\nimport type { ToolContext } from '../llm/tool_context.js';\nimport { log } from '../log.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport type { SpeechEvent } from '../stt/stt.js';\nimport { Future } from '../utils.js';\nimport type { ModelSettings } from './agent.js';\n\nexport type STTNode = (\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<SpeechEvent | string> | null>;\n\nexport type LLMNode = (\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<ChatChunk | string> | null>;\n\nexport type TTSNode = (\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<AudioFrame> | null>;\nexport abstract class AudioInput {\n protected deferredStream: DeferredReadableStream<AudioFrame> =\n new DeferredReadableStream<AudioFrame>();\n\n get stream(): ReadableStream<AudioFrame> {\n return this.deferredStream.stream;\n }\n\n onAttached(): void {}\n\n onDetached(): void {}\n}\n\nexport abstract class AudioOutput extends EventEmitter {\n static readonly EVENT_PLAYBACK_FINISHED = 'playbackFinished';\n\n private playbackFinishedFuture: Future<void> = new Future();\n private _capturing: boolean = false;\n private playbackFinishedCount: number = 0;\n private playbackSegmentsCount: number = 0;\n private lastPlaybackEvent: PlaybackFinishedEvent = {\n playbackPosition: 0,\n interrupted: false,\n };\n protected logger = log();\n\n constructor(\n readonly sampleRate?: number,\n protected readonly nextInChain?: AudioOutput,\n ) {\n super();\n if (this.nextInChain) {\n this.nextInChain.on(AudioOutput.EVENT_PLAYBACK_FINISHED, (ev: PlaybackFinishedEvent) =>\n this.onPlaybackFinished(ev),\n );\n }\n }\n\n /**\n * Capture an audio frame for playback, frames can be pushed faster than real-time\n */\n async captureFrame(_frame: AudioFrame): Promise<void> {\n if (!this._capturing) {\n this._capturing = true;\n this.playbackSegmentsCount++;\n }\n }\n\n /**\n * Wait for the past audio segments to finish playing out.\n *\n * @returns The event that was emitted when the audio finished playing out (only the last segment information)\n */\n async waitForPlayout(): Promise<PlaybackFinishedEvent> {\n const target = this.playbackSegmentsCount;\n\n while (this.playbackFinishedCount < target) {\n await this.playbackFinishedFuture.await;\n this.playbackFinishedFuture = new Future();\n }\n\n return this.lastPlaybackEvent;\n }\n\n /**\n * Developers building audio sinks must call this method when a playback/segment is finished.\n * Segments are segmented by calls to flush() or clearBuffer()\n */\n onPlaybackFinished(options: PlaybackFinishedEvent) {\n if (this.playbackFinishedCount >= this.playbackSegmentsCount) {\n this.logger.warn('playback_finished called more times than playback segments were captured');\n return;\n }\n\n this.lastPlaybackEvent = options;\n this.playbackFinishedCount++;\n this.playbackFinishedFuture.resolve();\n this.emit(AudioOutput.EVENT_PLAYBACK_FINISHED, options);\n }\n\n flush(): void {\n this._capturing = false;\n }\n\n /**\n * Clear the buffer, stopping playback immediately\n */\n abstract clearBuffer(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport interface PlaybackFinishedEvent {\n // How much of the audio was played back\n playbackPosition: number;\n // Interrupted is True if playback was interrupted (clearBuffer() was called)\n interrupted: boolean;\n // Transcript synced with playback; may be partial if the audio was interrupted\n // When null, the transcript is not synchronized with the playback\n synchronizedTranscript?: string;\n}\n\nexport abstract class TextOutput {\n constructor(protected readonly nextInChain?: TextOutput) {}\n\n /**\n * Capture a text segment (Used by the output of LLM nodes)\n */\n abstract captureText(text: string): Promise<void>;\n\n /**\n * Mark the current text segment as complete (e.g LLM generation is complete)\n */\n abstract flush(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport class AgentInput {\n private _audioStream: AudioInput | null = null;\n // enabled by default\n private _audioEnabled: boolean = true;\n\n constructor(private readonly audioChanged: () => void) {}\n\n setAudioEnabled(enable: boolean): void {\n if (enable === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enable;\n\n if (!this._audioStream) {\n return;\n }\n\n if (enable) {\n this._audioStream.onAttached();\n } else {\n this._audioStream.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get audio(): AudioInput | null {\n return this._audioStream;\n }\n\n set audio(stream: AudioInput | null) {\n this._audioStream = stream;\n this.audioChanged();\n }\n}\n\nexport class AgentOutput {\n private _audioSink: AudioOutput | null = null;\n private _transcriptionSink: TextOutput | null = null;\n private _audioEnabled: boolean = true;\n private _transcriptionEnabled: boolean = true;\n\n constructor(\n private readonly audioChanged: () => void,\n private readonly transcriptionChanged: () => void,\n ) {}\n\n setAudioEnabled(enabled: boolean): void {\n if (enabled === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enabled;\n\n if (!this._audioSink) {\n return;\n }\n\n if (enabled) {\n this._audioSink.onAttached();\n } else {\n this._audioSink.onDetached();\n }\n }\n\n setTranscriptionEnabled(enabled: boolean): void {\n if (enabled === this._transcriptionEnabled) {\n return;\n }\n\n this._transcriptionEnabled = enabled;\n\n if (!this._transcriptionSink) {\n return;\n }\n\n if (enabled) {\n this._transcriptionSink.onAttached();\n } else {\n this._transcriptionSink.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get transcriptionEnabled(): boolean {\n return this._transcriptionEnabled;\n }\n\n get audio(): AudioOutput | null {\n return this._audioSink;\n }\n\n set audio(sink: AudioOutput | null) {\n if (sink === this._audioSink) {\n return;\n }\n\n if (this._audioSink) {\n this._audioSink.onDetached();\n }\n\n this._audioSink = sink;\n this.audioChanged();\n\n if (this._audioSink) {\n this._audioSink.onAttached();\n }\n }\n\n get transcription(): TextOutput | null {\n return this._transcriptionSink;\n }\n\n set transcription(sink: TextOutput | null) {\n if (sink === this._transcriptionSink) {\n return;\n }\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onDetached();\n }\n\n this._transcriptionSink = sink;\n this.transcriptionChanged();\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onAttached();\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/io.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { EventEmitter } from 'node:events';\nimport type { ReadableStream } from 'node:stream/web';\nimport type { ChatContext } from '../llm/chat_context.js';\nimport type { ChatChunk } from '../llm/llm.js';\nimport type { ToolContext } from '../llm/tool_context.js';\nimport { log } from '../log.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport type { SpeechEvent } from '../stt/stt.js';\nimport { Future } from '../utils.js';\nimport type { ModelSettings } from './agent.js';\n\nexport type STTNode = (\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<SpeechEvent | string> | null>;\n\nexport type LLMNode = (\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<ChatChunk | string> | null>;\n\nexport type TTSNode = (\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n) => Promise<ReadableStream<AudioFrame> | null>;\nexport abstract class AudioInput {\n protected deferredStream: DeferredReadableStream<AudioFrame> =\n new DeferredReadableStream<AudioFrame>();\n\n get stream(): ReadableStream<AudioFrame> {\n return this.deferredStream.stream;\n }\n\n onAttached(): void {}\n\n onDetached(): void {}\n}\n\nexport abstract class AudioOutput extends EventEmitter {\n static readonly EVENT_PLAYBACK_FINISHED = 'playbackFinished';\n\n private playbackFinishedFuture: Future<void> = new Future();\n private _capturing: boolean = false;\n private playbackFinishedCount: number = 0;\n private playbackSegmentsCount: number = 0;\n private lastPlaybackEvent: PlaybackFinishedEvent = {\n playbackPosition: 0,\n interrupted: false,\n };\n protected logger = log();\n\n constructor(\n public sampleRate?: number,\n protected readonly nextInChain?: AudioOutput,\n ) {\n super();\n if (this.nextInChain) {\n this.nextInChain.on(AudioOutput.EVENT_PLAYBACK_FINISHED, (ev: PlaybackFinishedEvent) =>\n this.onPlaybackFinished(ev),\n );\n }\n }\n\n /**\n * Capture an audio frame for playback, frames can be pushed faster than real-time\n */\n async captureFrame(_frame: AudioFrame): Promise<void> {\n if (!this._capturing) {\n this._capturing = true;\n this.playbackSegmentsCount++;\n }\n }\n\n /**\n * Wait for the past audio segments to finish playing out.\n *\n * @returns The event that was emitted when the audio finished playing out (only the last segment information)\n */\n async waitForPlayout(): Promise<PlaybackFinishedEvent> {\n const target = this.playbackSegmentsCount;\n\n while (this.playbackFinishedCount < target) {\n await this.playbackFinishedFuture.await;\n this.playbackFinishedFuture = new Future();\n }\n\n return this.lastPlaybackEvent;\n }\n\n /**\n * Developers building audio sinks must call this method when a playback/segment is finished.\n * Segments are segmented by calls to flush() or clearBuffer()\n */\n onPlaybackFinished(options: PlaybackFinishedEvent) {\n if (this.playbackFinishedCount >= this.playbackSegmentsCount) {\n this.logger.warn('playback_finished called more times than playback segments were captured');\n return;\n }\n\n this.lastPlaybackEvent = options;\n this.playbackFinishedCount++;\n this.playbackFinishedFuture.resolve();\n this.emit(AudioOutput.EVENT_PLAYBACK_FINISHED, options);\n }\n\n flush(): void {\n this._capturing = false;\n }\n\n /**\n * Clear the buffer, stopping playback immediately\n */\n abstract clearBuffer(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport interface PlaybackFinishedEvent {\n // How much of the audio was played back\n playbackPosition: number;\n // Interrupted is True if playback was interrupted (clearBuffer() was called)\n interrupted: boolean;\n // Transcript synced with playback; may be partial if the audio was interrupted\n // When null, the transcript is not synchronized with the playback\n synchronizedTranscript?: string;\n}\n\nexport abstract class TextOutput {\n constructor(protected readonly nextInChain?: TextOutput) {}\n\n /**\n * Capture a text segment (Used by the output of LLM nodes)\n */\n abstract captureText(text: string): Promise<void>;\n\n /**\n * Mark the current text segment as complete (e.g LLM generation is complete)\n */\n abstract flush(): void;\n\n onAttached(): void {\n if (this.nextInChain) {\n this.nextInChain.onAttached();\n }\n }\n\n onDetached(): void {\n if (this.nextInChain) {\n this.nextInChain.onDetached();\n }\n }\n}\n\nexport class AgentInput {\n private _audioStream: AudioInput | null = null;\n // enabled by default\n private _audioEnabled: boolean = true;\n\n constructor(private readonly audioChanged: () => void) {}\n\n setAudioEnabled(enable: boolean): void {\n if (enable === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enable;\n\n if (!this._audioStream) {\n return;\n }\n\n if (enable) {\n this._audioStream.onAttached();\n } else {\n this._audioStream.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get audio(): AudioInput | null {\n return this._audioStream;\n }\n\n set audio(stream: AudioInput | null) {\n this._audioStream = stream;\n this.audioChanged();\n }\n}\n\nexport class AgentOutput {\n private _audioSink: AudioOutput | null = null;\n private _transcriptionSink: TextOutput | null = null;\n private _audioEnabled: boolean = true;\n private _transcriptionEnabled: boolean = true;\n\n constructor(\n private readonly audioChanged: () => void,\n private readonly transcriptionChanged: () => void,\n ) {}\n\n setAudioEnabled(enabled: boolean): void {\n if (enabled === this._audioEnabled) {\n return;\n }\n\n this._audioEnabled = enabled;\n\n if (!this._audioSink) {\n return;\n }\n\n if (enabled) {\n this._audioSink.onAttached();\n } else {\n this._audioSink.onDetached();\n }\n }\n\n setTranscriptionEnabled(enabled: boolean): void {\n if (enabled === this._transcriptionEnabled) {\n return;\n }\n\n this._transcriptionEnabled = enabled;\n\n if (!this._transcriptionSink) {\n return;\n }\n\n if (enabled) {\n this._transcriptionSink.onAttached();\n } else {\n this._transcriptionSink.onDetached();\n }\n }\n\n get audioEnabled(): boolean {\n return this._audioEnabled;\n }\n\n get transcriptionEnabled(): boolean {\n return this._transcriptionEnabled;\n }\n\n get audio(): AudioOutput | null {\n return this._audioSink;\n }\n\n set audio(sink: AudioOutput | null) {\n if (sink === this._audioSink) {\n return;\n }\n\n if (this._audioSink) {\n this._audioSink.onDetached();\n }\n\n this._audioSink = sink;\n this.audioChanged();\n\n if (this._audioSink) {\n this._audioSink.onAttached();\n }\n }\n\n get transcription(): TextOutput | null {\n return this._transcriptionSink;\n }\n\n set transcription(sink: TextOutput | null) {\n if (sink === this._transcriptionSink) {\n return;\n }\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onDetached();\n }\n\n this._transcriptionSink = sink;\n this.transcriptionChanged();\n\n if (this._transcriptionSink) {\n this._transcriptionSink.onAttached();\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -60,7 +60,7 @@ class ParticipantAudioInputStream extends import_io.AudioInput {
|
|
|
60
60
|
}
|
|
61
61
|
const participantValue = participant instanceof import_rtc_node.RemoteParticipant ? participant : this.room.remoteParticipants.get(participantIdentity);
|
|
62
62
|
if (participantValue) {
|
|
63
|
-
for (const publication of
|
|
63
|
+
for (const publication of participantValue.trackPublications.values()) {
|
|
64
64
|
if (publication.track && publication.source === import_rtc_node.TrackSource.SOURCE_MICROPHONE) {
|
|
65
65
|
this.onTrackSubscribed(publication.track, publication, participantValue);
|
|
66
66
|
break;
|
|
@@ -105,6 +105,7 @@ class ParticipantAudioInputStream extends import_io.AudioInput {
|
|
|
105
105
|
sampleRate: this.sampleRate,
|
|
106
106
|
numChannels: this.numChannels,
|
|
107
107
|
noiseCancellation: this.noiseCancellation
|
|
108
|
+
// TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting
|
|
108
109
|
});
|
|
109
110
|
}
|
|
110
111
|
async close() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n if (participantValue) {\n for (const publication of
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,sBASO;AAEP,iBAAoB;AACpB,mBAA+B;AAC/B,gBAA2B;AAEpB,MAAM,oCAAoC,qBAAW;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAA6C;AAAA,EAC7C,sBAAqC;AAAA,EACrC,aAAS,gBAAI;AAAA,EACrB,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,SAAK,KAAK,GAAG,0BAAU,iBAAiB,KAAK,iBAAiB;AAC9D,SAAK,KAAK,GAAG,0BAAU,kBAAkB,KAAK,kBAAkB;AAAA,EAClE;AAAA,EAEA,eAAe,aAAgD;AAC7D,SAAK,OAAO,MAAM,EAAE,YAAY,GAAG,iCAAiC;AACpE,UAAM,sBACJ,uBAAuB,oCAAoB,YAAY,WAAW;AAEpE,QAAI,KAAK,wBAAwB,qBAAqB;AACpD;AAAA,IACF;AACA,SAAK,sBAAsB;AAC3B,SAAK,YAAY;AAEjB,QAAI,CAAC,qBAAqB;AACxB;AAAA,IACF;AAEA,UAAM,mBACJ,uBAAuB,oCACnB,cACA,KAAK,KAAK,mBAAmB,IAAI,mBAAmB;AAI1D,QAAI,kBAAkB;AACpB,iBAAW,eAAe,iBAAiB,kBAAkB,OAAO,GAAG;AACrE,YAAI,YAAY,SAAS,YAAY,WAAW,4BAAY,mBAAmB;AAC7E,eAAK,kBAAkB,YAAY,OAAO,aAAa,gBAAgB;AACvE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBAAqB,CAC3B,aACA,gBACG;AAnFP;AAoFI,UACE,UAAK,gBAAL,mBAAkB,SAAQ,YAAY,OACtC,YAAY,aAAa,KAAK,qBAC9B;AACA;AAAA,IACF;AACA,SAAK,YAAY;AAGjB,eAAWA,gBAAe,YAAY,kBAAkB,OAAO,GAAG;AAChE,UACEA,aAAY,SACZ,KAAK,kBAAkBA,aAAY,OAAOA,cAAa,WAAW,GAClE;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAc;AACpB,QAAI,KAAK,eAAe,aAAa;AACnC,WAAK,eAAe,aAAa;AAAA,IACnC;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,oBAAoB,CAC1B,OACA,aACA,gBACY;AACZ,QACE,KAAK,wBAAwB,YAAY,YACzC,YAAY,WAAW,4BAAY,qBAClC,KAAK,eAAe,KAAK,YAAY,QAAQ,YAAY,KAC1D;AACA,aAAO;AAAA,IACT;AACA,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,eAAe;AAAA,UAClB,6BAAe;AAAA,QACb,QAAQ,KAAK,aAAa,KAAK;AAAA,QAC/B,YAAY,KAAK;AAAA,MACnB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,OAAgD;AACnE,WAAO,IAAI,4BAAY,OAAO;AAAA,MAC5B,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA;AAAA,IAE1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,KAAK,IAAI,0BAAU,iBAAiB,KAAK,iBAAiB;AAC/D,SAAK,KAAK,IAAI,0BAAU,kBAAkB,KAAK,kBAAkB;AACjE,SAAK,YAAY;AACjB,SAAK,eAAe,OAAO,OAAO;AAAA,EACpC;AACF;","names":["publication"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_input.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_input.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"_input.d.ts","sourceRoot":"","sources":["../../../src/voice/room_io/_input.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,iBAAiB,EAGjB,KAAK,IAAI,EAGV,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,qBAAa,2BAA4B,SAAQ,UAAU;IACzD,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAC,CAA2B;IACrD,OAAO,CAAC,WAAW,CAAuC;IAC1D,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,MAAM,CAAS;gBACX,EACV,IAAI,EACJ,UAAU,EACV,WAAW,EACX,iBAAiB,GAClB,EAAE;QACD,IAAI,EAAE,IAAI,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;KAC9C;IAWD,cAAc,CAAC,WAAW,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI;IAgC7D,OAAO,CAAC,kBAAkB,CAqBxB;IAEF,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,iBAAiB,CAqBvB;IAEF,OAAO,CAAC,YAAY;IASd,KAAK;CAMZ"}
|
|
@@ -42,7 +42,7 @@ class ParticipantAudioInputStream extends AudioInput {
|
|
|
42
42
|
}
|
|
43
43
|
const participantValue = participant instanceof RemoteParticipant ? participant : this.room.remoteParticipants.get(participantIdentity);
|
|
44
44
|
if (participantValue) {
|
|
45
|
-
for (const publication of
|
|
45
|
+
for (const publication of participantValue.trackPublications.values()) {
|
|
46
46
|
if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {
|
|
47
47
|
this.onTrackSubscribed(publication.track, publication, participantValue);
|
|
48
48
|
break;
|
|
@@ -87,6 +87,7 @@ class ParticipantAudioInputStream extends AudioInput {
|
|
|
87
87
|
sampleRate: this.sampleRate,
|
|
88
88
|
numChannels: this.numChannels,
|
|
89
89
|
noiseCancellation: this.noiseCancellation
|
|
90
|
+
// TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting
|
|
90
91
|
});
|
|
91
92
|
}
|
|
92
93
|
async close() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n if (participantValue) {\n for (const publication of
|
|
1
|
+
{"version":3,"sources":["../../../src/voice/room_io/_input.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport {\n AudioStream,\n type NoiseCancellationOptions,\n RemoteParticipant,\n type RemoteTrack,\n type RemoteTrackPublication,\n type Room,\n RoomEvent,\n TrackSource,\n} from '@livekit/rtc-node';\nimport type { ReadableStream } from 'node:stream/web';\nimport { log } from '../../log.js';\nimport { resampleStream } from '../../utils.js';\nimport { AudioInput } from '../io.js';\n\nexport class ParticipantAudioInputStream extends AudioInput {\n private room: Room;\n private sampleRate: number;\n private numChannels: number;\n private noiseCancellation?: NoiseCancellationOptions;\n private publication: RemoteTrackPublication | null = null;\n private participantIdentity: string | null = null;\n private logger = log();\n constructor({\n room,\n sampleRate,\n numChannels,\n noiseCancellation,\n }: {\n room: Room;\n sampleRate: number;\n numChannels: number;\n noiseCancellation?: NoiseCancellationOptions;\n }) {\n super();\n this.room = room;\n this.sampleRate = sampleRate;\n this.numChannels = numChannels;\n this.noiseCancellation = noiseCancellation;\n\n this.room.on(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.on(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n }\n\n setParticipant(participant: RemoteParticipant | string | null) {\n this.logger.debug({ participant }, 'setting participant audio input');\n const participantIdentity =\n participant instanceof RemoteParticipant ? participant.identity : participant;\n\n if (this.participantIdentity === participantIdentity) {\n return;\n }\n this.participantIdentity = participantIdentity;\n this.closeStream();\n\n if (!participantIdentity) {\n return;\n }\n\n const participantValue =\n participant instanceof RemoteParticipant\n ? participant\n : this.room.remoteParticipants.get(participantIdentity);\n\n // We need to check if the participant has a microphone track and subscribe to it\n // in case we miss the tracksubscribed event\n if (participantValue) {\n for (const publication of participantValue.trackPublications.values()) {\n if (publication.track && publication.source === TrackSource.SOURCE_MICROPHONE) {\n this.onTrackSubscribed(publication.track, publication, participantValue);\n break;\n }\n }\n }\n }\n\n private onTrackUnpublished = (\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ) => {\n if (\n this.publication?.sid !== publication.sid ||\n participant.identity !== this.participantIdentity\n ) {\n return;\n }\n this.closeStream();\n\n // subscribe to the first available track\n for (const publication of participant.trackPublications.values()) {\n if (\n publication.track &&\n this.onTrackSubscribed(publication.track, publication, participant)\n ) {\n return;\n }\n }\n };\n\n private closeStream() {\n if (this.deferredStream.isSourceSet) {\n this.deferredStream.detachSource();\n }\n this.publication = null;\n }\n\n private onTrackSubscribed = (\n track: RemoteTrack,\n publication: RemoteTrackPublication,\n participant: RemoteParticipant,\n ): boolean => {\n if (\n this.participantIdentity !== participant.identity ||\n publication.source !== TrackSource.SOURCE_MICROPHONE ||\n (this.publication && this.publication.sid === publication.sid)\n ) {\n return false;\n }\n this.closeStream();\n this.publication = publication;\n this.deferredStream.setSource(\n resampleStream({\n stream: this.createStream(track),\n outputRate: this.sampleRate,\n }),\n );\n return true;\n };\n\n private createStream(track: RemoteTrack): ReadableStream<AudioFrame> {\n return new AudioStream(track, {\n sampleRate: this.sampleRate,\n numChannels: this.numChannels,\n noiseCancellation: this.noiseCancellation,\n // TODO(AJS-269): resolve compatibility issue with node-sdk to remove the forced type casting\n }) as unknown as ReadableStream<AudioFrame>;\n }\n\n async close() {\n this.room.off(RoomEvent.TrackSubscribed, this.onTrackSubscribed);\n this.room.off(RoomEvent.TrackUnpublished, this.onTrackUnpublished);\n this.closeStream();\n this.deferredStream.stream.cancel();\n }\n}\n"],"mappings":"AAIA;AAAA,EACE;AAAA,EAEA;AAAA,EAIA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,WAAW;AACpB,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAEpB,MAAM,oCAAoC,WAAW;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAA6C;AAAA,EAC7C,sBAAqC;AAAA,EACrC,SAAS,IAAI;AAAA,EACrB,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,SAAK,KAAK,GAAG,UAAU,iBAAiB,KAAK,iBAAiB;AAC9D,SAAK,KAAK,GAAG,UAAU,kBAAkB,KAAK,kBAAkB;AAAA,EAClE;AAAA,EAEA,eAAe,aAAgD;AAC7D,SAAK,OAAO,MAAM,EAAE,YAAY,GAAG,iCAAiC;AACpE,UAAM,sBACJ,uBAAuB,oBAAoB,YAAY,WAAW;AAEpE,QAAI,KAAK,wBAAwB,qBAAqB;AACpD;AAAA,IACF;AACA,SAAK,sBAAsB;AAC3B,SAAK,YAAY;AAEjB,QAAI,CAAC,qBAAqB;AACxB;AAAA,IACF;AAEA,UAAM,mBACJ,uBAAuB,oBACnB,cACA,KAAK,KAAK,mBAAmB,IAAI,mBAAmB;AAI1D,QAAI,kBAAkB;AACpB,iBAAW,eAAe,iBAAiB,kBAAkB,OAAO,GAAG;AACrE,YAAI,YAAY,SAAS,YAAY,WAAW,YAAY,mBAAmB;AAC7E,eAAK,kBAAkB,YAAY,OAAO,aAAa,gBAAgB;AACvE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBAAqB,CAC3B,aACA,gBACG;AAnFP;AAoFI,UACE,UAAK,gBAAL,mBAAkB,SAAQ,YAAY,OACtC,YAAY,aAAa,KAAK,qBAC9B;AACA;AAAA,IACF;AACA,SAAK,YAAY;AAGjB,eAAWA,gBAAe,YAAY,kBAAkB,OAAO,GAAG;AAChE,UACEA,aAAY,SACZ,KAAK,kBAAkBA,aAAY,OAAOA,cAAa,WAAW,GAClE;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAc;AACpB,QAAI,KAAK,eAAe,aAAa;AACnC,WAAK,eAAe,aAAa;AAAA,IACnC;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,oBAAoB,CAC1B,OACA,aACA,gBACY;AACZ,QACE,KAAK,wBAAwB,YAAY,YACzC,YAAY,WAAW,YAAY,qBAClC,KAAK,eAAe,KAAK,YAAY,QAAQ,YAAY,KAC1D;AACA,aAAO;AAAA,IACT;AACA,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,eAAe;AAAA,MAClB,eAAe;AAAA,QACb,QAAQ,KAAK,aAAa,KAAK;AAAA,QAC/B,YAAY,KAAK;AAAA,MACnB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,OAAgD;AACnE,WAAO,IAAI,YAAY,OAAO;AAAA,MAC5B,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA;AAAA,IAE1B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,KAAK,IAAI,UAAU,iBAAiB,KAAK,iBAAiB;AAC/D,SAAK,KAAK,IAAI,UAAU,kBAAkB,KAAK,kBAAkB;AACjE,SAAK,YAAY;AACjB,SAAK,eAAe,OAAO,OAAO;AAAA,EACpC;AACF;","names":["publication"]}
|
|
@@ -26,10 +26,23 @@ class RunContext {
|
|
|
26
26
|
this.session = session;
|
|
27
27
|
this.speechHandle = speechHandle;
|
|
28
28
|
this.functionCall = functionCall;
|
|
29
|
+
this.initialStepIdx = speechHandle.numSteps - 1;
|
|
29
30
|
}
|
|
31
|
+
initialStepIdx;
|
|
30
32
|
get userData() {
|
|
31
33
|
return this.session.userData;
|
|
32
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Waits for the speech playout corresponding to this function call step.
|
|
37
|
+
*
|
|
38
|
+
* Unlike {@link SpeechHandle.waitForPlayout}, which waits for the full
|
|
39
|
+
* assistant turn to complete (including all function tools),
|
|
40
|
+
* this method only waits for the assistant's spoken response prior to running
|
|
41
|
+
* this tool to finish playing.
|
|
42
|
+
*/
|
|
43
|
+
async waitForPlayout() {
|
|
44
|
+
return this.speechHandle._waitForGeneration(this.initialStepIdx);
|
|
45
|
+
}
|
|
33
46
|
}
|
|
34
47
|
// Annotate the CommonJS export names for ESM import in node:
|
|
35
48
|
0 && (module.exports = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/run_context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { FunctionCall } from '../llm/chat_context.js';\nimport type { AgentSession } from './agent_session.js';\nimport type { SpeechHandle } from './speech_handle.js';\n\nexport type UnknownUserData = unknown;\n\nexport class RunContext<UserData = UnknownUserData> {\n constructor(\n public readonly session: AgentSession<UserData>,\n public readonly speechHandle: SpeechHandle,\n public readonly functionCall: FunctionCall,\n ) {
|
|
1
|
+
{"version":3,"sources":["../../src/voice/run_context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { FunctionCall } from '../llm/chat_context.js';\nimport type { AgentSession } from './agent_session.js';\nimport type { SpeechHandle } from './speech_handle.js';\n\nexport type UnknownUserData = unknown;\n\nexport class RunContext<UserData = UnknownUserData> {\n private readonly initialStepIdx: number;\n constructor(\n public readonly session: AgentSession<UserData>,\n public readonly speechHandle: SpeechHandle,\n public readonly functionCall: FunctionCall,\n ) {\n this.initialStepIdx = speechHandle.numSteps - 1;\n }\n get userData(): UserData {\n return this.session.userData;\n }\n\n /**\n * Waits for the speech playout corresponding to this function call step.\n *\n * Unlike {@link SpeechHandle.waitForPlayout}, which waits for the full\n * assistant turn to complete (including all function tools),\n * this method only waits for the assistant's spoken response prior to running\n * this tool to finish playing.\n */\n async waitForPlayout() {\n return this.speechHandle._waitForGeneration(this.initialStepIdx);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AASO,MAAM,WAAuC;AAAA,EAElD,YACkB,SACA,cACA,cAChB;AAHgB;AACA;AACA;AAEhB,SAAK,iBAAiB,aAAa,WAAW;AAAA,EAChD;AAAA,EAPiB;AAAA,EAQjB,IAAI,WAAqB;AACvB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,iBAAiB;AACrB,WAAO,KAAK,aAAa,mBAAmB,KAAK,cAAc;AAAA,EACjE;AACF;","names":[]}
|
|
@@ -6,7 +6,17 @@ export declare class RunContext<UserData = UnknownUserData> {
|
|
|
6
6
|
readonly session: AgentSession<UserData>;
|
|
7
7
|
readonly speechHandle: SpeechHandle;
|
|
8
8
|
readonly functionCall: FunctionCall;
|
|
9
|
+
private readonly initialStepIdx;
|
|
9
10
|
constructor(session: AgentSession<UserData>, speechHandle: SpeechHandle, functionCall: FunctionCall);
|
|
10
11
|
get userData(): UserData;
|
|
12
|
+
/**
|
|
13
|
+
* Waits for the speech playout corresponding to this function call step.
|
|
14
|
+
*
|
|
15
|
+
* Unlike {@link SpeechHandle.waitForPlayout}, which waits for the full
|
|
16
|
+
* assistant turn to complete (including all function tools),
|
|
17
|
+
* this method only waits for the assistant's spoken response prior to running
|
|
18
|
+
* this tool to finish playing.
|
|
19
|
+
*/
|
|
20
|
+
waitForPlayout(): Promise<void>;
|
|
11
21
|
}
|
|
12
22
|
//# sourceMappingURL=run_context.d.ts.map
|
|
@@ -6,7 +6,17 @@ export declare class RunContext<UserData = UnknownUserData> {
|
|
|
6
6
|
readonly session: AgentSession<UserData>;
|
|
7
7
|
readonly speechHandle: SpeechHandle;
|
|
8
8
|
readonly functionCall: FunctionCall;
|
|
9
|
+
private readonly initialStepIdx;
|
|
9
10
|
constructor(session: AgentSession<UserData>, speechHandle: SpeechHandle, functionCall: FunctionCall);
|
|
10
11
|
get userData(): UserData;
|
|
12
|
+
/**
|
|
13
|
+
* Waits for the speech playout corresponding to this function call step.
|
|
14
|
+
*
|
|
15
|
+
* Unlike {@link SpeechHandle.waitForPlayout}, which waits for the full
|
|
16
|
+
* assistant turn to complete (including all function tools),
|
|
17
|
+
* this method only waits for the assistant's spoken response prior to running
|
|
18
|
+
* this tool to finish playing.
|
|
19
|
+
*/
|
|
20
|
+
waitForPlayout(): Promise<void>;
|
|
11
21
|
}
|
|
12
22
|
//# sourceMappingURL=run_context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run_context.d.ts","sourceRoot":"","sources":["../../src/voice/run_context.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC;AAEtC,qBAAa,UAAU,CAAC,QAAQ,GAAG,eAAe;
|
|
1
|
+
{"version":3,"file":"run_context.d.ts","sourceRoot":"","sources":["../../src/voice/run_context.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC;AAEtC,qBAAa,UAAU,CAAC,QAAQ,GAAG,eAAe;aAG9B,OAAO,EAAE,YAAY,CAAC,QAAQ,CAAC;aAC/B,YAAY,EAAE,YAAY;aAC1B,YAAY,EAAE,YAAY;IAJ5C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAEtB,OAAO,EAAE,YAAY,CAAC,QAAQ,CAAC,EAC/B,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,YAAY;IAI5C,IAAI,QAAQ,IAAI,QAAQ,CAEvB;IAED;;;;;;;OAOG;IACG,cAAc;CAGrB"}
|
|
@@ -3,10 +3,23 @@ class RunContext {
|
|
|
3
3
|
this.session = session;
|
|
4
4
|
this.speechHandle = speechHandle;
|
|
5
5
|
this.functionCall = functionCall;
|
|
6
|
+
this.initialStepIdx = speechHandle.numSteps - 1;
|
|
6
7
|
}
|
|
8
|
+
initialStepIdx;
|
|
7
9
|
get userData() {
|
|
8
10
|
return this.session.userData;
|
|
9
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Waits for the speech playout corresponding to this function call step.
|
|
14
|
+
*
|
|
15
|
+
* Unlike {@link SpeechHandle.waitForPlayout}, which waits for the full
|
|
16
|
+
* assistant turn to complete (including all function tools),
|
|
17
|
+
* this method only waits for the assistant's spoken response prior to running
|
|
18
|
+
* this tool to finish playing.
|
|
19
|
+
*/
|
|
20
|
+
async waitForPlayout() {
|
|
21
|
+
return this.speechHandle._waitForGeneration(this.initialStepIdx);
|
|
22
|
+
}
|
|
10
23
|
}
|
|
11
24
|
export {
|
|
12
25
|
RunContext
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/run_context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { FunctionCall } from '../llm/chat_context.js';\nimport type { AgentSession } from './agent_session.js';\nimport type { SpeechHandle } from './speech_handle.js';\n\nexport type UnknownUserData = unknown;\n\nexport class RunContext<UserData = UnknownUserData> {\n constructor(\n public readonly session: AgentSession<UserData>,\n public readonly speechHandle: SpeechHandle,\n public readonly functionCall: FunctionCall,\n ) {
|
|
1
|
+
{"version":3,"sources":["../../src/voice/run_context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { FunctionCall } from '../llm/chat_context.js';\nimport type { AgentSession } from './agent_session.js';\nimport type { SpeechHandle } from './speech_handle.js';\n\nexport type UnknownUserData = unknown;\n\nexport class RunContext<UserData = UnknownUserData> {\n private readonly initialStepIdx: number;\n constructor(\n public readonly session: AgentSession<UserData>,\n public readonly speechHandle: SpeechHandle,\n public readonly functionCall: FunctionCall,\n ) {\n this.initialStepIdx = speechHandle.numSteps - 1;\n }\n get userData(): UserData {\n return this.session.userData;\n }\n\n /**\n * Waits for the speech playout corresponding to this function call step.\n *\n * Unlike {@link SpeechHandle.waitForPlayout}, which waits for the full\n * assistant turn to complete (including all function tools),\n * this method only waits for the assistant's spoken response prior to running\n * this tool to finish playing.\n */\n async waitForPlayout() {\n return this.speechHandle._waitForGeneration(this.initialStepIdx);\n }\n}\n"],"mappings":"AASO,MAAM,WAAuC;AAAA,EAElD,YACkB,SACA,cACA,cAChB;AAHgB;AACA;AACA;AAEhB,SAAK,iBAAiB,aAAa,WAAW;AAAA,EAChD;AAAA,EAPiB;AAAA,EAQjB,IAAI,WAAqB;AACvB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,iBAAiB;AACrB,WAAO,KAAK,aAAa,mBAAmB,KAAK,cAAc;AAAA,EACjE;AACF;","names":[]}
|