@livekit/agents-plugin-openai 0.2.0 → 0.3.1
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +28 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/realtime/api_proto.d.ts +399 -0
- package/dist/realtime/api_proto.d.ts.map +1 -0
- package/dist/realtime/api_proto.js +9 -0
- package/dist/realtime/api_proto.js.map +1 -0
- package/dist/realtime/index.d.ts +3 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +6 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/realtime_model.d.ts +149 -0
- package/dist/realtime/realtime_model.d.ts.map +1 -0
- package/dist/realtime/realtime_model.js +571 -0
- package/dist/realtime/realtime_model.js.map +1 -0
- package/package.json +5 -3
- package/src/index.ts +1 -2
- package/src/realtime/api_proto.ts +565 -0
- package/src/realtime/index.ts +5 -0
- package/src/realtime/realtime_model.ts +859 -0
- package/dist/omni_assistant/agent_playout.d.ts +0 -27
- package/dist/omni_assistant/agent_playout.d.ts.map +0 -1
- package/dist/omni_assistant/agent_playout.js +0 -111
- package/dist/omni_assistant/agent_playout.js.map +0 -1
- package/dist/omni_assistant/index.d.ts +0 -61
- package/dist/omni_assistant/index.d.ts.map +0 -1
- package/dist/omni_assistant/index.js +0 -453
- package/dist/omni_assistant/index.js.map +0 -1
- package/dist/omni_assistant/proto.d.ts +0 -218
- package/dist/omni_assistant/proto.d.ts.map +0 -1
- package/dist/omni_assistant/proto.js +0 -68
- package/dist/omni_assistant/proto.js.map +0 -1
- package/dist/omni_assistant/transcription_forwarder.d.ts +0 -28
- package/dist/omni_assistant/transcription_forwarder.d.ts.map +0 -1
- package/dist/omni_assistant/transcription_forwarder.js +0 -117
- package/dist/omni_assistant/transcription_forwarder.js.map +0 -1
- package/src/omni_assistant/agent_playout.ts +0 -127
- package/src/omni_assistant/index.ts +0 -547
- package/src/omni_assistant/proto.ts +0 -280
- package/src/omni_assistant/transcription_forwarder.ts +0 -128
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { Queue } from '@livekit/agents';
|
|
3
|
-
import { AudioFrame, type AudioSource } from '@livekit/rtc-node';
|
|
4
|
-
import { EventEmitter } from 'events';
|
|
5
|
-
import type { TranscriptionForwarder } from './transcription_forwarder';
|
|
6
|
-
export declare class AgentPlayout {
|
|
7
|
-
#private;
|
|
8
|
-
constructor(audioSource: AudioSource);
|
|
9
|
-
play(messageId: string, transcriptionFwd: TranscriptionForwarder): PlayoutHandle;
|
|
10
|
-
private playoutTask;
|
|
11
|
-
}
|
|
12
|
-
export declare class PlayoutHandle extends EventEmitter {
|
|
13
|
-
messageId: string;
|
|
14
|
-
transcriptionFwd: TranscriptionForwarder;
|
|
15
|
-
playedAudioSamples: number;
|
|
16
|
-
done: boolean;
|
|
17
|
-
interrupted: boolean;
|
|
18
|
-
playoutQueue: Queue<AudioFrame | null>;
|
|
19
|
-
constructor(messageId: string, transcriptionFwd: TranscriptionForwarder);
|
|
20
|
-
pushAudio(data: Uint8Array): void;
|
|
21
|
-
pushText(text: string): void;
|
|
22
|
-
endInput(): void;
|
|
23
|
-
interrupt(): void;
|
|
24
|
-
publishedTextChars(): number;
|
|
25
|
-
complete(): void;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=agent_playout.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent_playout.d.ts","sourceRoot":"","sources":["../../src/omni_assistant/agent_playout.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAExE,qBAAa,YAAY;;gBAKX,WAAW,EAAE,WAAW;IAMpC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,sBAAsB,GAAG,aAAa;YAYlE,WAAW;CAsC1B;AAED,qBAAa,aAAc,SAAQ,YAAY;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,sBAAsB,CAAC;IACzC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;gBAE3B,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,sBAAsB;IAUvE,SAAS,CAAC,IAAI,EAAE,UAAU;IAW1B,QAAQ,CAAC,IAAI,EAAE,MAAM;IAIrB,QAAQ;IAMR,SAAS;IAKT,kBAAkB,IAAI,MAAM;IAI5B,QAAQ;CAKT"}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
-
};
|
|
7
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
-
};
|
|
12
|
-
var _AgentPlayout_audioSource, _AgentPlayout_currentPlayoutHandle, _AgentPlayout_currentPlayoutTask;
|
|
13
|
-
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
14
|
-
//
|
|
15
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
16
|
-
import { AudioByteStream } from '@livekit/agents';
|
|
17
|
-
import { Queue } from '@livekit/agents';
|
|
18
|
-
import { AudioFrame } from '@livekit/rtc-node';
|
|
19
|
-
import { EventEmitter } from 'events';
|
|
20
|
-
import * as proto from './proto.js';
|
|
21
|
-
export class AgentPlayout {
|
|
22
|
-
constructor(audioSource) {
|
|
23
|
-
_AgentPlayout_audioSource.set(this, void 0);
|
|
24
|
-
_AgentPlayout_currentPlayoutHandle.set(this, void 0);
|
|
25
|
-
_AgentPlayout_currentPlayoutTask.set(this, void 0);
|
|
26
|
-
__classPrivateFieldSet(this, _AgentPlayout_audioSource, audioSource, "f");
|
|
27
|
-
__classPrivateFieldSet(this, _AgentPlayout_currentPlayoutHandle, null, "f");
|
|
28
|
-
__classPrivateFieldSet(this, _AgentPlayout_currentPlayoutTask, null, "f");
|
|
29
|
-
}
|
|
30
|
-
play(messageId, transcriptionFwd) {
|
|
31
|
-
if (__classPrivateFieldGet(this, _AgentPlayout_currentPlayoutHandle, "f")) {
|
|
32
|
-
__classPrivateFieldGet(this, _AgentPlayout_currentPlayoutHandle, "f").interrupt();
|
|
33
|
-
}
|
|
34
|
-
__classPrivateFieldSet(this, _AgentPlayout_currentPlayoutHandle, new PlayoutHandle(messageId, transcriptionFwd), "f");
|
|
35
|
-
__classPrivateFieldSet(this, _AgentPlayout_currentPlayoutTask, this.playoutTask(__classPrivateFieldGet(this, _AgentPlayout_currentPlayoutTask, "f"), __classPrivateFieldGet(this, _AgentPlayout_currentPlayoutHandle, "f")), "f");
|
|
36
|
-
return __classPrivateFieldGet(this, _AgentPlayout_currentPlayoutHandle, "f");
|
|
37
|
-
}
|
|
38
|
-
async playoutTask(oldTask, handle) {
|
|
39
|
-
let firstFrame = true;
|
|
40
|
-
try {
|
|
41
|
-
const bstream = new AudioByteStream(proto.SAMPLE_RATE, proto.NUM_CHANNELS, proto.OUTPUT_PCM_FRAME_SIZE);
|
|
42
|
-
while (!handle.interrupted) {
|
|
43
|
-
const frame = await handle.playoutQueue.get();
|
|
44
|
-
if (frame === null)
|
|
45
|
-
break;
|
|
46
|
-
if (firstFrame) {
|
|
47
|
-
handle.transcriptionFwd.start();
|
|
48
|
-
firstFrame = false;
|
|
49
|
-
}
|
|
50
|
-
for (const f of bstream.write(frame.data.buffer)) {
|
|
51
|
-
handle.playedAudioSamples += f.samplesPerChannel;
|
|
52
|
-
if (handle.interrupted)
|
|
53
|
-
break;
|
|
54
|
-
await __classPrivateFieldGet(this, _AgentPlayout_audioSource, "f").captureFrame(f);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (!handle.interrupted) {
|
|
58
|
-
for (const f of bstream.flush()) {
|
|
59
|
-
await __classPrivateFieldGet(this, _AgentPlayout_audioSource, "f").captureFrame(f);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
finally {
|
|
64
|
-
if (!firstFrame && !handle.interrupted) {
|
|
65
|
-
handle.transcriptionFwd.markTextComplete();
|
|
66
|
-
}
|
|
67
|
-
await handle.transcriptionFwd.close(handle.interrupted);
|
|
68
|
-
handle.complete();
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
_AgentPlayout_audioSource = new WeakMap(), _AgentPlayout_currentPlayoutHandle = new WeakMap(), _AgentPlayout_currentPlayoutTask = new WeakMap();
|
|
73
|
-
export class PlayoutHandle extends EventEmitter {
|
|
74
|
-
constructor(messageId, transcriptionFwd) {
|
|
75
|
-
super();
|
|
76
|
-
this.messageId = messageId;
|
|
77
|
-
this.transcriptionFwd = transcriptionFwd;
|
|
78
|
-
this.playedAudioSamples = 0;
|
|
79
|
-
this.done = false;
|
|
80
|
-
this.interrupted = false;
|
|
81
|
-
this.playoutQueue = new Queue();
|
|
82
|
-
}
|
|
83
|
-
pushAudio(data) {
|
|
84
|
-
const frame = new AudioFrame(new Int16Array(data.buffer), proto.SAMPLE_RATE, proto.NUM_CHANNELS, data.length / 2);
|
|
85
|
-
this.transcriptionFwd.pushAudio(frame);
|
|
86
|
-
this.playoutQueue.put(frame);
|
|
87
|
-
}
|
|
88
|
-
pushText(text) {
|
|
89
|
-
this.transcriptionFwd.pushText(text);
|
|
90
|
-
}
|
|
91
|
-
endInput() {
|
|
92
|
-
this.transcriptionFwd.markAudioComplete();
|
|
93
|
-
this.transcriptionFwd.markTextComplete();
|
|
94
|
-
this.playoutQueue.put(null);
|
|
95
|
-
}
|
|
96
|
-
interrupt() {
|
|
97
|
-
if (this.done)
|
|
98
|
-
return;
|
|
99
|
-
this.interrupted = true;
|
|
100
|
-
}
|
|
101
|
-
publishedTextChars() {
|
|
102
|
-
return this.transcriptionFwd.currentCharacterIndex;
|
|
103
|
-
}
|
|
104
|
-
complete() {
|
|
105
|
-
if (this.done)
|
|
106
|
-
return;
|
|
107
|
-
this.done = true;
|
|
108
|
-
this.emit('complete', this.interrupted);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
//# sourceMappingURL=agent_playout.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent_playout.js","sourceRoot":"","sources":["../../src/omni_assistant/agent_playout.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { llm } from '@livekit/agents';
|
|
2
|
-
import type { RemoteAudioTrack, RemoteParticipant, Room } from '@livekit/rtc-node';
|
|
3
|
-
import * as proto from './proto.js';
|
|
4
|
-
/** @hidden */
|
|
5
|
-
export declare const defaultSessionConfig: proto.SessionConfig;
|
|
6
|
-
/** @hidden */
|
|
7
|
-
export declare const defaultConversationConfig: proto.ConversationConfig;
|
|
8
|
-
type ImplOptions = {
|
|
9
|
-
apiKey: string;
|
|
10
|
-
sessionConfig: proto.SessionConfig;
|
|
11
|
-
conversationConfig: proto.ConversationConfig;
|
|
12
|
-
functions: llm.FunctionContext;
|
|
13
|
-
};
|
|
14
|
-
/** @alpha */
|
|
15
|
-
export declare class OmniAssistant {
|
|
16
|
-
options: ImplOptions;
|
|
17
|
-
room: Room | null;
|
|
18
|
-
linkedParticipant: RemoteParticipant | null;
|
|
19
|
-
subscribedTrack: RemoteAudioTrack | null;
|
|
20
|
-
readMicroTask: {
|
|
21
|
-
promise: Promise<void>;
|
|
22
|
-
cancel: () => void;
|
|
23
|
-
} | null;
|
|
24
|
-
constructor({ sessionConfig, conversationConfig, functions, apiKey, }: {
|
|
25
|
-
sessionConfig?: proto.SessionConfig;
|
|
26
|
-
conversationConfig?: proto.ConversationConfig;
|
|
27
|
-
functions?: llm.FunctionContext;
|
|
28
|
-
apiKey?: string;
|
|
29
|
-
});
|
|
30
|
-
private ws;
|
|
31
|
-
private connected;
|
|
32
|
-
private thinking;
|
|
33
|
-
private participant;
|
|
34
|
-
private agentPublication;
|
|
35
|
-
private localTrackSid;
|
|
36
|
-
private localSource;
|
|
37
|
-
private agentPlayout;
|
|
38
|
-
private playingHandle;
|
|
39
|
-
private logger;
|
|
40
|
-
get funcCtx(): llm.FunctionContext;
|
|
41
|
-
set funcCtx(ctx: llm.FunctionContext);
|
|
42
|
-
start(room: Room, participant?: RemoteParticipant | string | null): Promise<void>;
|
|
43
|
-
close(): void;
|
|
44
|
-
addUserMessage(text: string, generate?: boolean): void;
|
|
45
|
-
private setState;
|
|
46
|
-
private loggableEvent;
|
|
47
|
-
private sendClientCommand;
|
|
48
|
-
private handleServerEvent;
|
|
49
|
-
private handleAddContent;
|
|
50
|
-
private handleMessageAdded;
|
|
51
|
-
private handleInputTranscribed;
|
|
52
|
-
private handleGenerationCanceled;
|
|
53
|
-
private handleGenerationFinished;
|
|
54
|
-
private handleVadSpeechStarted;
|
|
55
|
-
private linkParticipant;
|
|
56
|
-
private subscribeToMicrophone;
|
|
57
|
-
private getLocalTrackSid;
|
|
58
|
-
private publishTranscription;
|
|
59
|
-
}
|
|
60
|
-
export {};
|
|
61
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/omni_assistant/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAO,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAGV,gBAAgB,EAChB,iBAAiB,EACjB,IAAI,EACL,MAAM,mBAAmB,CAAC;AAY3B,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAGpC,cAAc;AACd,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,aASxC,CAAC;AAEF,cAAc;AACd,eAAO,MAAM,yBAAyB,EAAE,KAAK,CAAC,kBAW7C,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC;IACnC,kBAAkB,EAAE,KAAK,CAAC,kBAAkB,CAAC;IAC7C,SAAS,EAAE,GAAG,CAAC,eAAe,CAAC;CAChC,CAAC;AAEF,aAAa;AACb,qBAAa,aAAa;IACxB,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IACzB,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IACnD,eAAe,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAChD,aAAa,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,GAAG,IAAI,CAAQ;gBAEhE,EACV,aAAoC,EACpC,kBAA8C,EAC9C,SAAc,EACd,MAAyC,GAC1C,EAAE;QACD,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QACpC,kBAAkB,CAAC,EAAE,KAAK,CAAC,kBAAkB,CAAC;QAC9C,SAAS,CAAC,EAAE,GAAG,CAAC,eAAe,CAAC;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;IAcD,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,WAAW,CAA2C;IAC9D,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,MAAM,CAAS;IAEvB,IAAI,OAAO,IAAI,GAAG,CAAC,eAAe,CAEjC;IACD,IAAI,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,eAAe,EAOnC;IAED,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,GAAE,iBAAiB,GAAG,MAAM,GAAG,IAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkFvF,KAAK;IAML,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,OAAc,GAAG,IAAI;IAoB5D,OAAO,CAAC,QAAQ;IAgBhB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,iBAAiB;IAkCzB,OAAO,CAAC,gBAAgB;IAsCxB,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,sBAAsB;IAiB9B,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,qBAAqB;IA0D7B,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,oBAAoB;CA2B7B"}
|
|
@@ -1,453 +0,0 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
|
-
//
|
|
3
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import { AudioByteStream } from '@livekit/agents';
|
|
5
|
-
import { findMicroTrackId } from '@livekit/agents';
|
|
6
|
-
import { llm, log } from '@livekit/agents';
|
|
7
|
-
import { AudioSource, AudioStream, AudioStreamEvent, LocalAudioTrack, RoomEvent, TrackPublishOptions, TrackSource, } from '@livekit/rtc-node';
|
|
8
|
-
import { WebSocket } from 'ws';
|
|
9
|
-
import { AgentPlayout } from './agent_playout.js';
|
|
10
|
-
import * as proto from './proto.js';
|
|
11
|
-
import { BasicTranscriptionForwarder } from './transcription_forwarder.js';
|
|
12
|
-
/** @hidden */
|
|
13
|
-
export const defaultSessionConfig = {
|
|
14
|
-
turn_detection: 'server_vad',
|
|
15
|
-
input_audio_format: proto.AudioFormat.PCM16,
|
|
16
|
-
transcribe_input: true,
|
|
17
|
-
vad: {
|
|
18
|
-
threshold: 0.5,
|
|
19
|
-
prefix_padding_ms: 300,
|
|
20
|
-
silence_duration_ms: 200,
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
/** @hidden */
|
|
24
|
-
export const defaultConversationConfig = {
|
|
25
|
-
system_message: 'You are a helpful assistant.',
|
|
26
|
-
voice: proto.Voice.ALLOY,
|
|
27
|
-
subscribe_to_user_audio: true,
|
|
28
|
-
output_audio_format: proto.AudioFormat.PCM16,
|
|
29
|
-
tools: [],
|
|
30
|
-
tool_choice: proto.ToolChoice.AUTO,
|
|
31
|
-
temperature: 0.8,
|
|
32
|
-
max_tokens: 2048,
|
|
33
|
-
disable_audio: false,
|
|
34
|
-
transcribe_input: true,
|
|
35
|
-
};
|
|
36
|
-
/** @alpha */
|
|
37
|
-
export class OmniAssistant {
|
|
38
|
-
constructor({ sessionConfig = defaultSessionConfig, conversationConfig = defaultConversationConfig, functions = {}, apiKey = process.env.OPENAI_API_KEY || '', }) {
|
|
39
|
-
this.room = null;
|
|
40
|
-
this.linkedParticipant = null;
|
|
41
|
-
this.subscribedTrack = null;
|
|
42
|
-
this.readMicroTask = null;
|
|
43
|
-
this.ws = null;
|
|
44
|
-
this.connected = false;
|
|
45
|
-
this.thinking = false;
|
|
46
|
-
this.participant = null;
|
|
47
|
-
this.agentPublication = null;
|
|
48
|
-
this.localTrackSid = null;
|
|
49
|
-
this.localSource = null;
|
|
50
|
-
this.agentPlayout = null;
|
|
51
|
-
this.playingHandle = null;
|
|
52
|
-
this.logger = log();
|
|
53
|
-
if (!apiKey) {
|
|
54
|
-
throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');
|
|
55
|
-
}
|
|
56
|
-
conversationConfig.tools = tools(functions);
|
|
57
|
-
this.options = {
|
|
58
|
-
apiKey,
|
|
59
|
-
sessionConfig,
|
|
60
|
-
conversationConfig,
|
|
61
|
-
functions,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
get funcCtx() {
|
|
65
|
-
return this.options.functions;
|
|
66
|
-
}
|
|
67
|
-
set funcCtx(ctx) {
|
|
68
|
-
this.options.functions = ctx;
|
|
69
|
-
this.options.conversationConfig.tools = tools(ctx);
|
|
70
|
-
this.sendClientCommand(Object.assign({ event: proto.ClientEventType.UPDATE_CONVERSATION_CONFIG }, this.options.conversationConfig));
|
|
71
|
-
}
|
|
72
|
-
start(room, participant = null) {
|
|
73
|
-
return new Promise(async (resolve, reject) => {
|
|
74
|
-
var _a;
|
|
75
|
-
if (this.ws !== null) {
|
|
76
|
-
this.logger.warn('VoiceAssistant already started');
|
|
77
|
-
resolve();
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
room.on(RoomEvent.ParticipantConnected, (participant) => {
|
|
81
|
-
if (!this.linkedParticipant) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
this.linkParticipant(participant.identity);
|
|
85
|
-
});
|
|
86
|
-
this.room = room;
|
|
87
|
-
this.participant = participant;
|
|
88
|
-
this.setState(proto.State.INITIALIZING);
|
|
89
|
-
this.localSource = new AudioSource(proto.SAMPLE_RATE, proto.NUM_CHANNELS);
|
|
90
|
-
this.agentPlayout = new AgentPlayout(this.localSource);
|
|
91
|
-
const track = LocalAudioTrack.createAudioTrack('assistant_voice', this.localSource);
|
|
92
|
-
const options = new TrackPublishOptions();
|
|
93
|
-
options.source = TrackSource.SOURCE_MICROPHONE;
|
|
94
|
-
this.agentPublication = (await ((_a = room.localParticipant) === null || _a === void 0 ? void 0 : _a.publishTrack(track, options))) || null;
|
|
95
|
-
if (!this.agentPublication) {
|
|
96
|
-
this.logger.error('Failed to publish track');
|
|
97
|
-
reject(new Error('Failed to publish track'));
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
await this.agentPublication.waitForSubscription();
|
|
101
|
-
if (participant) {
|
|
102
|
-
if (typeof participant === 'string') {
|
|
103
|
-
this.linkParticipant(participant);
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
this.linkParticipant(participant.identity);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
// No participant specified, try to find the first participant in the room
|
|
111
|
-
for (const participant of room.remoteParticipants.values()) {
|
|
112
|
-
this.linkParticipant(participant.identity);
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
this.ws = new WebSocket(proto.API_URL, {
|
|
117
|
-
headers: {
|
|
118
|
-
Authorization: `Bearer ${this.options.apiKey}`,
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
this.ws.onopen = () => {
|
|
122
|
-
this.connected = true;
|
|
123
|
-
this.sendClientCommand(Object.assign({ event: proto.ClientEventType.UPDATE_SESSION_CONFIG }, this.options.sessionConfig));
|
|
124
|
-
this.sendClientCommand(Object.assign({ event: proto.ClientEventType.UPDATE_CONVERSATION_CONFIG }, this.options.conversationConfig));
|
|
125
|
-
resolve();
|
|
126
|
-
};
|
|
127
|
-
this.ws.onerror = (error) => {
|
|
128
|
-
reject(error);
|
|
129
|
-
};
|
|
130
|
-
this.ws.onclose = () => {
|
|
131
|
-
this.connected = false;
|
|
132
|
-
this.ws = null;
|
|
133
|
-
};
|
|
134
|
-
this.ws.onmessage = (message) => {
|
|
135
|
-
this.handleServerEvent(JSON.parse(message.data));
|
|
136
|
-
};
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
// user-initiated close
|
|
140
|
-
close() {
|
|
141
|
-
if (!this.connected || !this.ws)
|
|
142
|
-
return;
|
|
143
|
-
this.logger.debug('stopping assistant');
|
|
144
|
-
this.ws.close();
|
|
145
|
-
}
|
|
146
|
-
addUserMessage(text, generate = true) {
|
|
147
|
-
this.sendClientCommand({
|
|
148
|
-
event: proto.ClientEventType.ADD_MESSAGE,
|
|
149
|
-
message: {
|
|
150
|
-
role: 'user',
|
|
151
|
-
content: [
|
|
152
|
-
{
|
|
153
|
-
type: 'text',
|
|
154
|
-
text: text,
|
|
155
|
-
},
|
|
156
|
-
],
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
|
-
if (generate) {
|
|
160
|
-
this.sendClientCommand({
|
|
161
|
-
event: proto.ClientEventType.GENERATE,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
setState(state) {
|
|
166
|
-
var _a;
|
|
167
|
-
// don't override thinking until done
|
|
168
|
-
if (this.thinking)
|
|
169
|
-
return;
|
|
170
|
-
if (((_a = this.room) === null || _a === void 0 ? void 0 : _a.isConnected) && this.room.localParticipant) {
|
|
171
|
-
const currentState = this.room.localParticipant.attributes['voice_assistant.state'];
|
|
172
|
-
if (currentState !== state) {
|
|
173
|
-
this.room.localParticipant.setAttributes({
|
|
174
|
-
'voice_assistant.state': state,
|
|
175
|
-
});
|
|
176
|
-
this.logger.debug(`voice_assistant.state updated from ${currentState} to ${state}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/// Truncates the data field of the event to the specified maxLength to avoid overwhelming logs
|
|
181
|
-
/// with large amounts of base64 audio data.
|
|
182
|
-
loggableEvent(event, maxLength = 30) {
|
|
183
|
-
const untypedEvent = {};
|
|
184
|
-
for (const [key, value] of Object.entries(event)) {
|
|
185
|
-
if (value !== undefined) {
|
|
186
|
-
untypedEvent[key] = value;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (untypedEvent.data && typeof untypedEvent.data === 'string') {
|
|
190
|
-
const truncatedData = untypedEvent.data.slice(0, maxLength) + (untypedEvent.data.length > maxLength ? '…' : '');
|
|
191
|
-
return Object.assign(Object.assign({}, untypedEvent), { data: truncatedData });
|
|
192
|
-
}
|
|
193
|
-
return untypedEvent;
|
|
194
|
-
}
|
|
195
|
-
sendClientCommand(command) {
|
|
196
|
-
const isAudio = command.event === proto.ClientEventType.ADD_USER_AUDIO;
|
|
197
|
-
if (!this.connected || !this.ws) {
|
|
198
|
-
if (!isAudio)
|
|
199
|
-
this.logger.error('WebSocket is not connected');
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
if (!isAudio) {
|
|
203
|
-
this.logger.debug(`-> ${JSON.stringify(this.loggableEvent(command))}`);
|
|
204
|
-
}
|
|
205
|
-
this.ws.send(JSON.stringify(command));
|
|
206
|
-
}
|
|
207
|
-
handleServerEvent(event) {
|
|
208
|
-
this.logger.debug(`<- ${JSON.stringify(this.loggableEvent(event))}`);
|
|
209
|
-
switch (event.event) {
|
|
210
|
-
case proto.ServerEventType.START_SESSION:
|
|
211
|
-
this.setState(proto.State.LISTENING);
|
|
212
|
-
break;
|
|
213
|
-
case proto.ServerEventType.ADD_MESSAGE:
|
|
214
|
-
break;
|
|
215
|
-
case proto.ServerEventType.ADD_CONTENT:
|
|
216
|
-
this.handleAddContent(event);
|
|
217
|
-
break;
|
|
218
|
-
case proto.ServerEventType.MESSAGE_ADDED:
|
|
219
|
-
this.handleMessageAdded(event);
|
|
220
|
-
break;
|
|
221
|
-
case proto.ServerEventType.VAD_SPEECH_STARTED:
|
|
222
|
-
this.handleVadSpeechStarted(event);
|
|
223
|
-
break;
|
|
224
|
-
case proto.ServerEventType.VAD_SPEECH_STOPPED:
|
|
225
|
-
break;
|
|
226
|
-
case proto.ServerEventType.INPUT_TRANSCRIBED:
|
|
227
|
-
this.handleInputTranscribed(event);
|
|
228
|
-
break;
|
|
229
|
-
case proto.ServerEventType.GENERATION_CANCELED:
|
|
230
|
-
this.handleGenerationCanceled();
|
|
231
|
-
break;
|
|
232
|
-
case proto.ServerEventType.GENERATION_FINISHED:
|
|
233
|
-
this.handleGenerationFinished(event);
|
|
234
|
-
break;
|
|
235
|
-
default:
|
|
236
|
-
this.logger.warn(`Unknown server event: ${JSON.stringify(event)}`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
handleAddContent(event) {
|
|
240
|
-
var _a, _b, _c, _d;
|
|
241
|
-
if (event.event !== proto.ServerEventType.ADD_CONTENT)
|
|
242
|
-
return;
|
|
243
|
-
const trackSid = this.getLocalTrackSid();
|
|
244
|
-
if (!this.room || !this.room.localParticipant || !trackSid || !this.agentPlayout) {
|
|
245
|
-
log().error('Room or local participant not set');
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
if (!this.playingHandle || this.playingHandle.done) {
|
|
249
|
-
const trFwd = new BasicTranscriptionForwarder(this.room, (_b = (_a = this.room) === null || _a === void 0 ? void 0 : _a.localParticipant) === null || _b === void 0 ? void 0 : _b.identity, trackSid, event.message_id);
|
|
250
|
-
this.setState(proto.State.SPEAKING);
|
|
251
|
-
this.playingHandle = this.agentPlayout.play(event.message_id, trFwd);
|
|
252
|
-
this.playingHandle.on('complete', () => {
|
|
253
|
-
this.setState(proto.State.LISTENING);
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
switch (event.type) {
|
|
257
|
-
case 'audio':
|
|
258
|
-
(_c = this.playingHandle) === null || _c === void 0 ? void 0 : _c.pushAudio(Buffer.from(event.data, 'base64'));
|
|
259
|
-
break;
|
|
260
|
-
case 'text':
|
|
261
|
-
(_d = this.playingHandle) === null || _d === void 0 ? void 0 : _d.pushText(event.data);
|
|
262
|
-
break;
|
|
263
|
-
case 'tool_call':
|
|
264
|
-
break;
|
|
265
|
-
default:
|
|
266
|
-
this.logger.warn(`Unknown content event type: ${event.type}`);
|
|
267
|
-
break;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
handleMessageAdded(event) {
|
|
271
|
-
if (event.event !== proto.ServerEventType.MESSAGE_ADDED)
|
|
272
|
-
return;
|
|
273
|
-
for (const toolCall of event.content || []) {
|
|
274
|
-
this.options.functions[toolCall.name].execute(toolCall.arguments).then((content) => {
|
|
275
|
-
this.thinking = false;
|
|
276
|
-
this.sendClientCommand({
|
|
277
|
-
event: proto.ClientEventType.ADD_MESSAGE,
|
|
278
|
-
message: {
|
|
279
|
-
role: 'tool',
|
|
280
|
-
tool_call_id: toolCall.tool_call_id,
|
|
281
|
-
content: [
|
|
282
|
-
{
|
|
283
|
-
type: 'text',
|
|
284
|
-
text: content,
|
|
285
|
-
},
|
|
286
|
-
],
|
|
287
|
-
},
|
|
288
|
-
});
|
|
289
|
-
this.sendClientCommand({
|
|
290
|
-
event: proto.ClientEventType.GENERATE,
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
break;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
handleInputTranscribed(event) {
|
|
297
|
-
var _a, _b;
|
|
298
|
-
if (event.event !== proto.ServerEventType.INPUT_TRANSCRIBED)
|
|
299
|
-
return;
|
|
300
|
-
const messageId = event.message_id;
|
|
301
|
-
const transcription = event.transcript;
|
|
302
|
-
if (!messageId || transcription === undefined) {
|
|
303
|
-
this.logger.error('Message ID or transcription not set');
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
const participantIdentity = (_a = this.linkedParticipant) === null || _a === void 0 ? void 0 : _a.identity;
|
|
307
|
-
const trackSid = (_b = this.subscribedTrack) === null || _b === void 0 ? void 0 : _b.sid;
|
|
308
|
-
if (participantIdentity && trackSid) {
|
|
309
|
-
this.publishTranscription(participantIdentity, trackSid, transcription, true, messageId);
|
|
310
|
-
}
|
|
311
|
-
else {
|
|
312
|
-
this.logger.error('Participant or track not set');
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
handleGenerationCanceled() {
|
|
316
|
-
if (this.playingHandle && !this.playingHandle.done) {
|
|
317
|
-
this.playingHandle.interrupt();
|
|
318
|
-
this.sendClientCommand({
|
|
319
|
-
event: proto.ClientEventType.TRUNCATE_CONTENT,
|
|
320
|
-
message_id: this.playingHandle.messageId,
|
|
321
|
-
index: 0, // ignored for now (see OAI docs)
|
|
322
|
-
text_chars: this.playingHandle.publishedTextChars(),
|
|
323
|
-
audio_samples: this.playingHandle.playedAudioSamples,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
handleGenerationFinished(event) {
|
|
328
|
-
if (event.event !== proto.ServerEventType.GENERATION_FINISHED)
|
|
329
|
-
return;
|
|
330
|
-
if (event.reason !== 'interrupt' && event.reason !== 'stop') {
|
|
331
|
-
log().warn(`assistant turn finished unexpectedly reason ${event.reason}`);
|
|
332
|
-
}
|
|
333
|
-
if (this.playingHandle && !this.playingHandle.interrupted) {
|
|
334
|
-
this.playingHandle.endInput();
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
handleVadSpeechStarted(event) {
|
|
338
|
-
var _a, _b;
|
|
339
|
-
if (event.event !== proto.ServerEventType.VAD_SPEECH_STARTED)
|
|
340
|
-
return;
|
|
341
|
-
const messageId = event.message_id;
|
|
342
|
-
const participantIdentity = (_a = this.linkedParticipant) === null || _a === void 0 ? void 0 : _a.identity;
|
|
343
|
-
const trackSid = (_b = this.subscribedTrack) === null || _b === void 0 ? void 0 : _b.sid;
|
|
344
|
-
if (participantIdentity && trackSid && messageId) {
|
|
345
|
-
this.publishTranscription(participantIdentity, trackSid, '', false, messageId);
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
this.logger.error('Participant or track or itemId not set');
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
linkParticipant(participantIdentity) {
|
|
352
|
-
if (!this.room) {
|
|
353
|
-
this.logger.error('Room is not set');
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
this.linkedParticipant = this.room.remoteParticipants.get(participantIdentity) || null;
|
|
357
|
-
if (!this.linkedParticipant) {
|
|
358
|
-
this.logger.error(`Participant with identity ${participantIdentity} not found`);
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
if (this.linkedParticipant.trackPublications.size > 0) {
|
|
362
|
-
this.subscribeToMicrophone();
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
this.room.on(RoomEvent.TrackPublished, () => {
|
|
366
|
-
this.subscribeToMicrophone();
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
subscribeToMicrophone() {
|
|
371
|
-
const readAudioStreamTask = async (audioStream) => {
|
|
372
|
-
const bstream = new AudioByteStream(proto.SAMPLE_RATE, proto.NUM_CHANNELS, proto.INPUT_PCM_FRAME_SIZE);
|
|
373
|
-
audioStream.on(AudioStreamEvent.FrameReceived, (ev) => {
|
|
374
|
-
const audioData = ev.frame.data;
|
|
375
|
-
for (const frame of bstream.write(audioData.buffer)) {
|
|
376
|
-
this.sendClientCommand({
|
|
377
|
-
event: proto.ClientEventType.ADD_USER_AUDIO,
|
|
378
|
-
data: Buffer.from(frame.data.buffer).toString('base64'),
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
};
|
|
383
|
-
if (!this.linkedParticipant) {
|
|
384
|
-
this.logger.error('Participant is not set');
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
for (const publication of this.linkedParticipant.trackPublications.values()) {
|
|
388
|
-
if (publication.source !== TrackSource.SOURCE_MICROPHONE) {
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
if (!publication.subscribed) {
|
|
392
|
-
publication.setSubscribed(true);
|
|
393
|
-
}
|
|
394
|
-
const track = publication.track;
|
|
395
|
-
if (track && track !== this.subscribedTrack) {
|
|
396
|
-
this.subscribedTrack = track;
|
|
397
|
-
if (this.readMicroTask) {
|
|
398
|
-
this.readMicroTask.cancel();
|
|
399
|
-
}
|
|
400
|
-
let cancel;
|
|
401
|
-
this.readMicroTask = {
|
|
402
|
-
promise: new Promise((resolve, reject) => {
|
|
403
|
-
cancel = () => {
|
|
404
|
-
// Cleanup logic here
|
|
405
|
-
reject(new Error('Task cancelled'));
|
|
406
|
-
};
|
|
407
|
-
readAudioStreamTask(new AudioStream(track, proto.SAMPLE_RATE, proto.NUM_CHANNELS))
|
|
408
|
-
.then(resolve)
|
|
409
|
-
.catch(reject);
|
|
410
|
-
}),
|
|
411
|
-
cancel: () => cancel(),
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
getLocalTrackSid() {
|
|
417
|
-
var _a;
|
|
418
|
-
if (!this.localTrackSid && this.room && this.room.localParticipant) {
|
|
419
|
-
this.localTrackSid = findMicroTrackId(this.room, (_a = this.room.localParticipant) === null || _a === void 0 ? void 0 : _a.identity);
|
|
420
|
-
}
|
|
421
|
-
return this.localTrackSid;
|
|
422
|
-
}
|
|
423
|
-
publishTranscription(participantIdentity, trackSid, text, isFinal, id) {
|
|
424
|
-
var _a;
|
|
425
|
-
if (!((_a = this.room) === null || _a === void 0 ? void 0 : _a.localParticipant)) {
|
|
426
|
-
log().error('Room or local participant not set');
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
this.room.localParticipant.publishTranscription({
|
|
430
|
-
participantIdentity,
|
|
431
|
-
trackSid,
|
|
432
|
-
segments: [
|
|
433
|
-
{
|
|
434
|
-
text,
|
|
435
|
-
final: isFinal,
|
|
436
|
-
id,
|
|
437
|
-
startTime: BigInt(0),
|
|
438
|
-
endTime: BigInt(0),
|
|
439
|
-
language: '',
|
|
440
|
-
},
|
|
441
|
-
],
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
const tools = (ctx) => Object.entries(ctx).map(([name, func]) => ({
|
|
446
|
-
type: 'function',
|
|
447
|
-
function: {
|
|
448
|
-
name,
|
|
449
|
-
description: func.description,
|
|
450
|
-
parameters: llm.oaiParams(func.parameters),
|
|
451
|
-
},
|
|
452
|
-
}));
|
|
453
|
-
//# sourceMappingURL=index.js.map
|